2017-12-01 3 views
2

Ich habe zwei Versionen von Java-Code, die Benutzereingabe, bis Benutzertypen "q" Version 1 bekommt:Java unter Verwendung von Scanner mit Try-mit-Ressourcen

public class Test { 
    public static void main(String[] args) { 
     String input = ""; 
     while (!input.equals("q")) { 
      Scanner scanner = new Scanner(System.in); 
      System.out.print("Input: "); 
      input = scanner.nextLine(); 
      System.out.println("Input was: " + input); 
     } 
    } 
} 

Version 2:

public class Test { 
    public static void main(String[] args) { 
     String input = ""; 
     while (!input.equals("q")) { 
      try(Scanner scanner = new Scanner(System.in)){ 
       System.out.print("Input: "); 
       input = scanner.nextLine(); 
       System.out.println("Input was: " + input); 
      } 
     } 
    } 
} 

Version 1 funktioniert wie erwartet, aber Version 2 funktioniert nicht wie erwartet. Das ist nach Benutzereingabe zum ersten Mal zu lesen, einen Fehler

Input: 12 
Input was: 12Exception in thread "main" 
Input: java.util.NoSuchElementException: No line found 
    at java.util.Scanner.nextLine(Scanner.java:1540) 
    at RealEstateCompany.main(RealEstateCompany.java:115) 

Meine Vermutung ist, seit der Version 2 verwendet versuchen, mit Ressource erzeugt, so dass es den Scanner nach dem Gebrauch schließt wurde und dass ein Fehler verursacht?

Vielen Dank für Ihre Hilfe im Voraus!

[Update] Version 3:

public class Test { 
    public static void main(String[] args) { 
     String input = ""; 
     try(Scanner scanner = new Scanner(System.in)){ 
      while (!input.equals("q")) { 
       System.out.print("Input: "); 
       input = scanner.nextLine(); 
       System.out.println("Input was: " + input); 
      } 
     } 
    } 
} 

Version 3 funktioniert. Warum ist Version 3 jedoch in Ordnung und Version 2 ist nicht in Ordnung?

+2

'try-with' schließt automatisch den zugrundeliegenden' Scanner', der automatisch den zugrunde liegenden Stream schließt, der 'System.in' ist. Danach können Sie keine Benutzereingaben mehr erhalten. – QBrute

+0

Haben Sie versucht, versuchen (Scanner Scanner = neue Scanner (System.in)) außerhalb der While-Schleife? –

+0

@RajuSharma Vielen Dank für Ihren Rat. Ja, es hat mein Problem gelöst, aber warum löst das das Problem? – ksn

Antwort

1

Hinzufügen von ein wenig ausführlicher auf meine Kommentare

Ein try-with Block wird wie folgt definiert:

try(...) { 
    ... 
} 

wo das Argument in Klammern eine Instanz von java.lang.AutoCloseable sein muss. Ein Beispiel ist die Klasse java.io.InputStream, die auch die Klasse System.in ist.

Ein versucht, die bereitgestellte Ressource automatisch zu schließen, sobald der Block verlassen wurde. Abhängig von der verwendeten Ressource schließt es alle seine eigenen untergeordneten Ressourcen. In Ihrem Beispiel haben Sie try(Scanner scanner = new Scanner(System.in)), die Scanner als Ressource verwendet. Der Scanner selbst verwendet System.in als Ressource. Sobald der try Block übrig ist (wenn } erreicht ist), versucht er, seine Ressourcen zu schließen, was die Scanner Instanz ist. Diese Instanz versucht auch, seine Ressource, die System.in zu schließen.

Sobald System.in geschlossen ist, können Sie keine Eingabe von der Konsole mehr bekommen (zumindest nicht mit etwas zusätzlicher Arbeit, denke ich ...).

Konkret in Ihrem zweiten Beispiel:

while (!input.equals("q")) { 
    try(Scanner scanner = new Scanner(System.in)){ 
      ... 
    } // <--- The block is left, scanner is closed, System.in is closed 
} // <-- start a new iteration 

Hier nach nur einer Iteration wird System.in geschlossen.Sicher, Sie erstellen eine neue Scanner in der nächsten Iteration, aber System.inbleibt geschlossen, deshalb erhalten Sie Ihre Ausnahme in diesem Fall.

Ihr drittes Beispiel:

try(Scanner scanner = new Scanner(System.in)){ 
    while (!input.equals("q")) { 
     ... 
    } // <-- start a new iteration, while still in the same try block 
} // <-- only after the while, your resources are closed 

Hier Sie Looping Ihre while, während noch intry zu sein. So wird keine Ressource geschlossen, bis Sie while und try verlassen. Das heißt, der eine Scanner bleibt intakt und mit ihm der eine System.in. Auf diese Weise können Sie so lange von der Konsole aus lesen, bis Sie mit dem Schleifen fertig sind.

+0

Vielen Dank für die klarste Erklärung. Jetzt fühle ich mich viel besser mit Probieren mit Ressourcen! – ksn

0

Try this:

String input = ""; 
    try (Scanner scanner = new Scanner(System.in)) { 
     while (!input.equals("q")) { 
      System.out.print("Input: "); 
      input = scanner.nextLine(); 
      System.out.println("Input was: " + input); 
     } 
    } 

Sie können jede Klasse das ist, verwenden implementiert Closeable oder AutoCloseable in Try-mit-Ressourcen, wenn Code, um das Ende des try Anruf erreicht, rufen Sie close() Funktion der Scanner Klasse in unser Beispiel.

+0

Sie sollten zumindest erklären, warum das funktioniert. – AxelH

+0

Ist das nicht grundsätzlich Version 3 in OPs post? – notyou

+0

@Gal Vielen Dank für Ihre Antwort und Erklärung. Das einzige, was ich jetzt nicht verstehe, ist, warum Version 2 nicht funktioniert. Ich habe verstanden, dass am Ende von try close() aufgerufen wird und der Scanner geschlossen ist, aber in der zweiten Iteration, in try (Scanner scanner = new ...) erstellt er die neue Scanner-Instanz neu, so dass ich denke, dass es in der Lage sein sollte, Eingaben zu lesen ein Mal noch. – ksn

0

i laufen einige Tests und fügen Sie den catch-Block in den Code Ihres code.here

public static void main(String[] args) { 
    String input = ""; 
    while (!input.equals("q")) { 
     try(Scanner scanner = new Scanner(System.in)){ 
      System.out.print("Input: "); 
      input = scanner.nextLine(); 
      System.out.println("Input was: " + input); 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
     }    
    } 
} 

, wenn der Block Fang hinzufügen, gibt es 2 Arten von Ergebnissen 1, nur q eingibt, arbeitet wie erwartet 2, gibt andere String, Exception

Input: java.util.NoSuchElementException: No line found 
at java.util.Scanner.nextLine(Scanner.java:1585) 
at rews.pub.Test.main(Test.java:11) 

wenn den Fangblock hinzugefügt, wir werden sehen, dass das Programm nicht auf, weil die while-Schleife

hier ist ein weiterer einfacher Test

public class Test { 
public static void main(String[] args) { 
    String input = ""; 
    Scanner scanner = new Scanner(System.in); 
    System.out.println("inout--1---"); 
    input = scanner.nextLine(); 
    scanner.close(); 

    Scanner scanner2 = new Scanner(System.in); 
    System.out.println("inout--2---"); 
    input = scanner2.nextLine(); 
    scanner2.close(); 

} 

}

und es geht gleiche Ausnahme

inout--1--- 
11 
inout--2--- 
Exception in thread "main" java.util.NoSuchElementException: No line found 
at java.util.Scanner.nextLine(Scanner.java:1585) 
at rews.pub.Test.main(Test.java:15) 

hier ist meine Meinung. am Ende des ersten Laufs, try() Block wird die Ressource schließen, die im Block ist, bedeutet, dass wir das system.in schließen system.in ist ein Objekt von inputSteam, und system.in ist endgültig und statisch, können wir öffne es nicht wie 'neuer Scanner (System.in)'