0

I'm trying to run my program in a loop and it runs perfectly fine the first time, but once it loops over and tries to find the nextLine, it crashes. My only issue with this is that I have a variable that is assigned by scanner.nextLine() then it delimits it. Shouldn't it ask for input every time instead of erroring?

private static List<String> readInput()
   {

      ArrayList<String> inputtedWords = new ArrayList<String>(); // creates an ArrayList called inputtedWords
      Scanner kb = new Scanner(System.in); //creating a scanner kb (keyboard)

      System.out.println("Text: "); // user input for Text:

      String fullText = kb.nextLine(); 
      Scanner s = new Scanner(fullText).useDelimiter(" "); //parses the fullText string and separates them on spaces

      while(s.hasNext()) // loops until their is not another word 
      {
         String tempStr = s.next();
         if (!Character.isAlphabetic(tempStr.charAt(tempStr.length()-1)))
            tempStr = tempStr.substring(0, tempStr.length()-1);

         inputtedWords.add(tempStr);
      }
      s.close();//closing scanners
      kb.close();//closing scanners
      return inputtedWords; // returns the inputtedWords list
   }

This is the code for the beginning of the loop...

List<String> dictionary = readDictionary(); // creates a List called dictionary and sets it equal to the file in method "readDictionary"

      while (done) // Change this to a while loop and negate it.  Remember to get another line of input at the end of the loop.
      {

         List<String> inputtedWords = readInput(); // creates another List for the words inputted into the method "readInput"
         if ((inputtedWords.size() == 1) && (inputtedWords.get(0).equals("done")))
         {
             done = false;
            System.out.println("Exiting Program");
            continue;
         }

      for  (String newWord : inputtedWords) // newWord = word inputted
      { // beginning of for loop, initializes element as a string then searches loops through the length of inputtedWords

         List<String> possibleAnswers = new ArrayList<>(); //creates an ArrayList called "possibleAnswers" 
         possibleAnswers.add(newWord); // adds the newly created word into the possibleAnswers list

         List<String> characters = new ArrayList<String>(); // creates another ArrayList called "chars"

I've been working on a fix for this for a while but cannot seem to figure out why it's erroring on me.

mossy
  • 61
  • 7
  • Can you provide the stack trace of the error? – Itami Feb 05 '20 at 01:00
  • Exception in thread "main" java.util.NoSuchElementException: No line found at java.util.Scanner.nextLine(Unknown Source) at TextCorrect.readInput(TextCorrect.java:168) at TextCorrect.main(TextCorrect.java:19) @Itami – mossy Feb 05 '20 at 01:07
  • 1
    Does this answer your question? [java.util.NoSuchElementException - Scanner reading user input](https://stackoverflow.com/questions/13042008/java-util-nosuchelementexception-scanner-reading-user-input) – Scratte Feb 05 '20 at 01:37

2 Answers2

0

On you code,

private static List<String> readInput(){
    //Your other code here 
    Scanner kb = new Scannr(System.in); //creating a scanner kb (keyboard)

    //Your other code here
    String fullText = kb.nextLine(); // read from user input
    //Your other code here

}

this Error was encountered due to the loop here

while (done){
    List<String> inputtedWords = readInput();
    //Your other code here 
}

base on Oracle documentation for Java here. And I quote:

public String nextLine() Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line. Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.

Returns: the line that was skipped

Throws: NoSuchElementException - if no line was found

It is recommended to add kb.hasNextLine() as validation to avoid the exception.

private static List<String> readInput(){
    //Your other code here 
    Scanner kb = new Scannr(System.in); //creating a scanner kb (keyboard)

    //Your other code here
    String fullText =  kb.hasNextLine() ? kb.nextLine() :""; // read from user input with validation

    //Or you can use. Use only one of these codes.
    String fullText = ""; // read from user input with validation
    if(kb.hasNextLine()){
         fullText = kb.nextLine();
    }
    //Your other code here

}

But you might get an infinite loop from that code.

You can solve the infinite loop by moving the variable of kb into static class attribute like

private static Scanner kb = null;
private static List<String> readInput(){
    //Your other code here 
    //kb = new Scannr(System.in); creating a scanner kb (keyboard) ***REMOVE this line***
    Scanner s = new Scanner(fullText).useDelimiter(" "); //parses the fullText string and separates them on spaces. ***This should be fine to where it is.****

    //Your other code here
    String fullText = kb.nextLine(); // read from user input
    //Your other code here
    s.close();//closing scanners  ***This should be fine to where it is.****
    //kb.close();  closing scanners ***REMOVE this from here***
}

Then move innitialization of scanner and kb.close(); outside your loop. like:

kb = new Scannr(System.in);
while (done){
    List<String> inputtedWords = readInput();
    //Your other code here 
}
kb.close();  closing scanner

If you don't want scanner as static attribute of the class, you can just send scanner as argument of the method like:

private static List<String> readInput(Scanner kb){

    //Your other code here
    String fullText =  kb.hasNextLine() ? kb.nextLine() :""; // read from user input with validation

    //Your other code here

}

On your loop

Scanner kb = new Scannr(System.in);
while (done){
    List<String> inputtedWords = readInput(kb);
    //Your other code here 
}
kb.close();  closing scanner
Itami
  • 78
  • 1
  • 8
  • I think the `NoSuchElementException` is a result of an underlying `java.io.IOException: Stream closed` that happens because closing is recursively applied when the `Scanner` is closed. If you put a `System.out.println(System.in.available());` before opening the scanner, it throws this error on the second run. – Scratte Feb 05 '20 at 02:18
  • I think so too. So I have advised in my answer to add a validation if there is a nextLine available. Then moving out the initialization of kb(Scanner for keyboar input), and closing of kb outside the loop. – Itami Feb 05 '20 at 02:46
  • I found it in the documentation `When a Scanner is closed, it will close its input source if the source implements the Closeable interface.` and `...underlying readable also implements the Closeable interface then the readable's close method will be invoked...` I wonder what happens it's just not closed. – Scratte Feb 05 '20 at 02:54
  • return and throws were also part of the quoted part from oracle. I didn't notice that it goes outside the quoted area. – Itami Feb 05 '20 at 02:54
  • Surely, there will be no stream to be found except for the case where the `underlying readable ` were reopened by the Scanner. I think. – Itami Feb 05 '20 at 02:57
  • I took it from java 11. The first quote is from the introduction. The other is from the close() method itself. I found this [Scanner is never closed](https://stackoverflow.com/questions/15613626/scanner-is-never-closed) where the answer **after** the accepted answer clearly states not to close a resource unless opened. Scanner is just a class, not a resource. So if you didn't open `System.in`, don't close it. – Scratte Feb 05 '20 at 03:01
  • The underlying readable is `System.in` in this case. The `Scanner` will not reopen it. – Scratte Feb 05 '20 at 03:03
  • 1
    I get the point that you don't need to explicitly calling close of Scanner. I just don't really know the reason why mossy need to close it, perhaps due to memory or other reasons. Personally, I don't use close of Scanner. Closing of Scanner with param of System.in should be done only **once** if the program **really** needs to close it. Or just ignore the closing of Scanner and leave it to JVM since it has its own garbage collector. – Itami Feb 05 '20 at 03:14
0

Moving the kb.close() outside of the loop fixed the whole thing.

mossy
  • 61
  • 7