13

Whenever I run this, the chooseCave() function works fine with the in.nextInt(). When I choose the cave, the messages pop up at 2-second intervals, and then as soon as it gets past that part, it gives me the error:

Exception in thread "main" java.util.NoSuchElementException: No line found
    at java.util.Scanner.nextLine(Unknown Source)
    at Dragon.main(Dragon.java:81)

I have tried hasNextLine() and hasNextInt(), and when I use while hasNextLine() in the main method, I get a ton more errors. When I use while hasNextInt() in the chooseCave() method, it doesn't accept my input.

When I use if hasNextInt() in the chooseCave() method, it doesn't accept my input for the playAgain string, and goes straight into another game, but then the hasNextInt() boolean returns false and it spams "Which cave..." infinitely.

I've gone through the error reports and the Java-docs and Stack Overflow's with similar problems. Please help.

import java.util.Scanner;
public class Dragon {

public static void displayIntro() {
    System.out.println("You are in a land full of dragons. In front of you, ");
    System.out.println("You see two caves. In one cave, the dragon is friendly");
    System.out.println("and will share his treasure with you. The other dragon");
    System.out.println("is greedy and hungry, and will eat you on sight");
    System.out.println(' ');
}

public static int chooseCave() {
    Scanner in = new Scanner(System.in);
    int cave = 0;
    while (cave != 1 && cave != 2) {
        System.out.println("Which cave will you go into? (1 or 2)");

        cave = in.nextInt();

    }
    in.close();
    return cave;
} 

public static void checkCave(int chosenCave) {
    System.out.println("You approach the cave...");
    try
       {
       // Sleep at least n milliseconds.
       // 1 millisecond = 1/1000 of a second.
       Thread.sleep( 2000 );
       }
    catch ( InterruptedException e )
       {
       System.out.println( "awakened prematurely" );
       }
    System.out.println("It is dark and spooky...");
    try
       {
       // Sleep at least n milliseconds.
       // 1 millisecond = 1/1000 of a second.
       Thread.sleep( 2000 );
       }
    catch ( InterruptedException e )
       {
       System.out.println( "awakened prematurely" );
       }
    System.out.println("A large dragon jumps out in front of you! He opens his jaws and...");
    try
       {
       // Sleep at least n milliseconds.
       // 1 millisecond = 1/1000 of a second.
       Thread.sleep( 2000 );
       }
    catch ( InterruptedException e )
       {
       System.out.println( "awakened prematurely" );
       }

    double friendlyCave = Math.ceil(Math.random() * 2);

    if (chosenCave == friendlyCave) {
        System.out.println("Gives you his treasure!");
    }
    else {
        System.out.println("Gobbles you down in one bite!");
    }



}
public static void main(String[] args) {
    Scanner inner = new Scanner(System.in);
    String playAgain = "yes";
    boolean play = true;
    while (play) {
        displayIntro();
        int caveNumber = chooseCave();
        checkCave(caveNumber);
        System.out.println("Do you want to play again? (yes or no)");
        playAgain = inner.nextLine();
        if (playAgain == "yes") {
            play = true;
        }
        else {
            play = false;
        }
    }
    inner.close();

}

}
syb0rg
  • 7,747
  • 7
  • 38
  • 77
Isaac Smith
  • 143
  • 1
  • 1
  • 4

5 Answers5

18

You close the second Scanner which closes the underlying InputStream, therefore the first Scanner can no longer read from the same InputStream and a NoSuchElementException results.

The solution: For console apps, use a single Scanner to read from System.in.

Aside: As stated already, be aware that Scanner#nextInt does not consume newline characters. Ensure that these are consumed before attempting to call nextLine again by using Scanner#newLine().

See: Do not create multiple buffered wrappers on a single InputStream

Reimeus
  • 152,723
  • 12
  • 195
  • 261
  • +1, I forgot to mention the multiple Scanners with one input problem. – syb0rg Mar 14 '13 at 00:37
  • Thanks to you and syb0rg. I just had to delete the method with the scanner in it and place the equivalent in the main method. It works! First success in a new programming language... feels really good. :) – Isaac Smith Mar 15 '13 at 08:49
7

The nextInt() method leaves the \n (end line) symbol and is picked up immediately by nextLine(), skipping over the next input. What you want to do is use nextLine() for everything, and parse it later:

String nextIntString = keyboard.nextLine(); //get the number as a single line
int nextInt = Integer.parseInt(nextIntString); //convert the string to an int

This is by far the easiest way to avoid problems--don't mix your "next" methods. Use only nextLine() and then parse ints or separate words afterwards.


Also, make sure you use only one Scanner if your are only using one terminal for input. That could be another reason for the exception.


Last note: compare a String with the .equals() function, not the == operator.

if (playAgain == "yes"); // Causes problems
if (playAgain.equals("yes")); // Works every time
syb0rg
  • 7,747
  • 7
  • 38
  • 77
  • Thank you! I wish I had enough points on here to upvote you. I fixed what you said, and it still didn't work... but the good news is, once I took the scanner out of the method, I was able to just put it all in the main method and it worked fine. Helped with number initializing too. Thanks again! :) – Isaac Smith Mar 14 '13 at 16:01
4

simply don't close in

remove in.close() from your code.

Abhishek Goel
  • 15,517
  • 8
  • 81
  • 62
  • This duplicates the accepted answer, but at a much lower quality. – JasonMArcher Oct 30 '14 at 18:23
  • I was also facing the same problem.. After searching a lot on internet and finally removing in.close() from my code worked for me. That's why I've answered this. – Abhishek Goel Oct 30 '14 at 18:29
  • This answer was really already given, and with a much better explanation. – Andrew Barber Nov 01 '14 at 04:11
  • @AndrewBarber can you tell me which answers tells to remove in.close(). I know I have not provided any explanation but the answer is right. Accepted answer tells to use only 1 scanner ( which sometimes is not possible ), I have said don't close the scanner at all. There is difference in both answers ( if you read carefully ). – Abhishek Goel Nov 01 '14 at 12:56
1

Reimeus is right, you see this because of in.close in your chooseCave(). Also, this is wrong.

if (playAgain == "yes") {
      play = true;
}

You should use equals instead of "==".

if (playAgain.equals("yes")) {
      play = true;
}
cwhsu
  • 1,353
  • 20
  • 29
1

Everyone explained pretty well on it. Let me answer when should this class be used.

When Should You Use NoSuchElementException?

Java includes a few different ways to iterate through elements in a collection. The first of these classes, Enumeration, was introduced in JDK1.0 and is generally considered deprecated in favor of newer iteration classes, like Iterator and ListIterator.

As with most programming languages, the Iterator class includes a hasNext() method that returns a boolean indicating if the iteration has anymore elements. If hasNext() returns true, then the next() method will return the next element in the iteration. Unlike Enumeration, Iterator also has a remove() method, which removes the last element that was obtained via next().

While Iterator is generalized for use with all collections in the Java Collections Framework, ListIterator is more specialized and only works with List-based collections, like ArrayList, LinkedList, and so forth. However, ListIterator adds even more functionality by allowing iteration to traverse in both directions via hasPrevious() and previous() methods.

vik_78
  • 1,018
  • 2
  • 12
  • 19