2016-09-30 3 views
1

Wir müssen etwas von einem lexikalischen Analysator machen, und ich hatte einige Probleme mit einer bestimmten Funktion von mir, useLoad, oder genauer gesagt, was passiert in Main, nachdem useLoad verwendet wurde.Ich kann nicht sehen, warum mein Scanner in Java eine "NoSuchElementException" wirft

Ich fand heraus, dass das war, weil ... aus irgendeinem Grund, buffer=keyboard.nextLine() wirft den Fehler, weil es aus irgendeinem Grund nicht mehr Eingabe von der Tastatur bekommt. Ich dachte, dass .nextLine() es zwingen sollte, mehr Eingabe vom Benutzer zu bekommen. Und ich weiß nicht, warum es genau nach dieser einen Methode diese Ausnahme auslöst. Es kann andere Methoden gut machen und nicht seine Fähigkeit zu lesen verlieren. Liegt es daran, dass ich eine Variable namens Tastatur in einem anderen Objekt habe und diese geschlossen habe? Das scheint zweifelhaft. Ich habe gerade versucht, den Namen zu ändern. Hat keinen Unterschied gemacht.

Variablen, die im folgenden Code verwendet, aber nicht deklariert wurden: Schlüsselwörter [0] ist der String "load". initial = Die Scanner-Zeichenfolge, die an die Funktion übergeben wird. offset = eine Zählervariable, um zu sehen, wie weit wir in der Zeile sind, die wir gelesen haben. Die UseLoad-Funktion (die meiner Meinung nach irgendwie kaputt ist), ist unten, aber ich habe alles, was sie durchläuft (mit jeder Methode durch eine horizontale Regel getrennt), in chronologischer Reihenfolge eingefügt, nur für den Fall I Ich sehe einfach nicht, was vor sich geht.

public static void main(String[] args) { 
     Scanner keyboard = new Scanner(System.in); //the scanner for keyboard 
     int i = 0; 
     String buffer =""; 
     boolean loopControl == true; 
     SymbolTable mySym = new SymbolTable(); 

     System.out.println("READY FOR INPUT\n"); 

     while (loopControl == true){ 
      //read in the line 
      buffer = ""; 
      buffer = keyboard.nextLine(); 
      if(!mySym.checkStop(buffer)){ //if we didn't stop 
       mySym.primary(buffer); 
      } 
      else{//if we did stop 
       closeLoop(); 
      } 

      if (i >= 55){ 
       loopControl = false; 
       System.out.println(("You have gone over the limit ("+i+" lines) per execution. Please continue by running this program again.").toUpperCase()); 
       //just a safety precaution...you know... in case closeLoop doesn't work 
      } 
      i++; 
     } 


     keyboard.close(); 

    } 

if(initial.substring(0, Keywords[0].length()).equals(Keywords[0])){ //Load 
     //if this is working as expected, then we simply need to do what the keyword says to do. 
     offset += Keywords[0].length(); //we have moved this much deeper in to the line 
     useLoad(offset, initial); 
     offset = 0; //just make sure, once we are done with the line, we start back at the start of the next line. 
     return; //we found what we were looking for, get out. 
    } 

private void useLoad(int offsetIn, String readIn) { 
     double doubIn = 0; 
     //now get the value of the 
     Scanner keyboard = new Scanner(System.in); //the scanner for keyboard 
      System.out.println("\nENTER VALUE FOR " + readIn.toUpperCase()); 
      doubIn = keyboard.nextDouble();  
     keyboard.close(); 

     variables.create(readIn.substring(offsetIn), doubIn); 
    } 
+1

Wo initialisieren Sie das 'loopControl'? – beatrice

+1

'keyboard.close();' schließt die Tastatur (duh), so dass Sie nichts tippen oder lesen können. (Eigentlich ist das nicht * ganz * korrekt, aber nahe genug) – immibis

+0

@beatrice Es war eine globale Variable in der Klasse von main (so dass andere Methoden damit umgehen konnten, wie closeLoop()). Deshalb wurde es nicht kopiert. Ich habe das vergessen. Ich habe es als lokale Variable hinzugefügt, da es keinen großen Unterschied macht. –

Antwort

0

Ich glaube, ich habe Ihr Problem gelöst.

Java-Dokumentation für beide Java 7 und 8 enthalten diese Zeile in Scanners schließen Methode Dokumentation:

Wenn dieser Scanner noch nicht dann geschlossen, wenn die zugrunde liegende lesbar implementiert auch die Closeable Schnittstelle dann die close Methode des lesbar wird aufgerufen.

Blick in die Dokumentation für System, die ich gefunden habe, dass System.in vom Typ InputStream, die, Sie ahnen es, implementiert Closeable. Die close Methodendokumentation für sagt, dass es nichts tut; InputStream ist jedoch abstract und close ist nicht markiert als final, was bedeutet, dass es überschrieben werden kann. System.in gibt eine InputStream zurück, die potenziell - und eindeutig tut - etwas tun könnte.

Also das Problem ist, erstellen Sie mehr Scanner s mit System.in, und jedes Mal, wenn Sie in der Nähe einen von ihnen, Sie schließen System.in, es unbrauchbar machen!

Dieses Problem wurde tatsächlich in einer anderen Frage here diskutiert, mit einer Lösung gegeben. Das heißt, für Ihr Programm würde ich einen von zwei Ansätzen vorschlagen:

  • Der erste Ansatz genannt wird: Entweder eine vorgefertigte Wrapper-Klasse verwenden oder ein eigenes, das einen InputStream in seinem Konstruktor akzeptiert. Lassen Sie diese Klasse 'InputStream Implementierung rufen Sie alle Methoden des umschlossenen Objekts, mit Ausnahme der close Methode, die ein No-Sell ist, und übergeben Sie dann Wrapper(System.in) an Scanner anstelle von System.in direkt. Allerdings würde ich vorsichtig sein, diesen Ansatz zu nehmen, außer in ganz bestimmten Umständen, denn jedes Mal, wenn Sie einen dieser Wrapper verwenden, müssen Sie sich an das eingewickelte Objekt am Ende der Verwendung erinnern, es sei denn, es ist etwas wie System.in.
  • Zweiter Ansatz: Verwenden Sie eine Runner-Klasse in Ihrem Programm und initialisieren Sie den Scanner dort. Übergeben Sie den Scanner während der Konstruktion an die erforderlichen Objekte, damit diese einen Verweis darauf halten können, und ermöglichen Sie ihnen dann, die erforderlichen Aufgaben abzuschließen, ohne den Scanner innerhalb der Klasse zu schließen. Sobald die Ausgangsbedingung angegeben wurde, kehren Sie von dort zur Runner-Klasse und zum close Scanner zurück.
+0

Um ehrlich zu sein, hat @immibis das tatsächlich vor mir gesagt, aber es wurde nicht sehr klar erklärt, weil Ihr Eingabe-Leser eigentlich "Tastatur" heißt. Sie versuchten zu sagen, was ich jetzt sage - dass die 'close' Methode des' System.in'-Scanners die Tastatur selbst "schließt" – BHustus

+0

Ich denke, Sie könnten Recht haben .. Ich hatte ähnlichen Verdacht. Die Arbeit an meinem Lisp-Programm bereitet mir Kopfschmerzen. Ich werde versuchen, das umzusetzen, was du am Morgen gesagt hast. –

0

Sie schließen die keyboard jedes Mal durch die Schleife. Deshalb liest man beim zweiten Mal von einem geschlossenen keyboard Objekt.

Ein kurzer Blick auf die Dokumentation für Scanner.nextLine enthält die Nachricht, dass es werfen könnte:

NoSuchElementException - if no line was found 
+0

Hoppla, tut mir leid. Das war von, als ich ctrl + z 1 weniger Male verwendete, als ich dachte, dass ich tat. Ich habe das behoben und bekomme immer noch den gleichen Fehler. –

+0

Sie sollten wahrscheinlich hasNextLine vor dem Aufruf von nextLine aufrufen. Ich bin mit Scanner nicht besonders vertraut, aber im Allgemeinen folgen Java-Methoden einem haveNext/next-Muster. Das doc für hasNextLine sagt, es könnte für die Eingabe blockieren, für nextLine sagt es nichts. – dave

+0

hmm? Ich dachte, dass nextLine und ebenfalls nextDouble es von der Tastatur eingelesen haben (oder aber der Scanner wurde initialisiert). Ich werde es versuchen. –

Verwandte Themen