1
boolean loop = false;
double numberOfStudents;


System.out.print("Enter a number: ");

if ((scnr.nextLine().trim().isEmpty()) ) {
    loop = true;
}

while (loop) {
    System.out.println("Enter a number");

    if (scnr.hasNextDouble() ){
        System.out.println("Loop has stopped");
        numberOfStudents = scnr.nextDouble();
        loop = false;
    }

}           

System.out.println("You're outside the loop!");

I'm trying to get the program to say "Enter a number" until the user has entered an actual number (no white spaces or letters or signs). When the user has entered a number, it sets numberOfStudents equal to that number and breaks out of the loop.

But if you hit enter twice, it doesn't iterate. It only displays "Enter a number" once.

What is wrong with the loop logic? Why isn't it looping until valid input is taken?

Inzimam Tariq IT
  • 5,936
  • 8
  • 32
  • 61
Neo
  • 395
  • 1
  • 3
  • 13

9 Answers9

3

For the actual answer to your question of "Why doesn't 'Enter a number' display more than once?" see Tom's comment (update: Tom's answer).

I've rewritten your loop in a way which preserves your code, but also makes it a little easier to handle format exceptions (though at the risk of silently swallowing an exception -- should be acceptable for this use case).

Can be up to you to use this design, here is an SO post on why empty catch blocks can be a bad practice.

public static void main(String args[])
{
    boolean loop = true;
    double numberOfStudents;
    Scanner scnr = new Scanner(System.in);

    while(loop){
        System.out.print("Enter a number: ");

        String input = scnr.nextLine();
        try{
            numberOfStudents = Double.parseDouble(input);
            loop = false;
        }catch(NumberFormatException e){
        }
    }
    System.out.println("You're outside the loop!");
}

Output:

Enter a number:
Enter a number:
Enter a number:
Enter a number: 50
You're outside the loop!

Community
  • 1
  • 1
CubeJockey
  • 2,191
  • 8
  • 22
  • 31
3

While trobbins code basically solves your problem, it's bad practice to use exceptions for flow control.

I used a small regexp to check if the value is a number. But this example is not complete, it will still crash it the user enters for example two decimal points. So you would need to create a proper number check or just use integers where the check is much easier.

Someone in the comments pointed out that people may want to enter scientific notation like 5e10, so this would also be another case to check for. If this is just some code you need as a proof of concept or something quick and dirty, you can go with the exception handling method but in production code you should avoid using exceptions this way.

double numberOfStudents;
Scanner scnr = new Scanner(System.in);

while(true) {
    System.out.print("Enter a number: ");
    String input = scnr.nextLine().trim();

    if(input.matches("^[0-9\\.]{1,}$")) {
        System.out.println("Loop has stopped");
        numberOfStudents = Double.parseDouble(input);
        break;
    }
}

System.out.println("You're outside the loop!");
Patrick Ziegler
  • 381
  • 1
  • 8
  • 12
  • 2
    *"`hasNextDouble` doesn't wait for input, it just checks if there is any."* too bad, that this is wrong :(. – Tom Sep 25 '15 at 17:12
  • Your solution addresses OP's problem, but fails on the rare use case where user enters a number in scientific notation, i.e. `1e10`. It's still a good answer – CubeJockey Sep 25 '15 at 17:21
  • @Trobbins It also fails in the first sentence :P, but yes, the rest is ok. – Tom Sep 25 '15 at 17:48
  • Well at least that's how I thought it worked. Looks like I got some reading to do – Patrick Ziegler Sep 25 '15 at 18:48
3

First of all: Since you're reading from System.in a call to the input stream will block until the user entered a valid token.

So let's check first scan using your scnr variable:

scnr.nextLine()

nextLine() reads everything til the next line delimiter. So if you just press return, then it will successfully read it and will perform the next stuff.

The next call is:

scnr.hasNextDouble()

This call expects a "real" token and ignores white spaces, except as a delimiter between tokens. So if you just press return again it doesn't actually read that input. So it still waits for more (for the first token). That is why it stucks in your loop and you won't get another "Enter a number" output.

You can fix that by either enter a real token, like a number, or by changing the loop like trobbins said.

I hope you now understand your program flow a bit more :).

Community
  • 1
  • 1
Tom
  • 14,120
  • 16
  • 41
  • 47
2

The following code should help you:

    double numberOfStudents = 0;
    Scanner scnr = new Scanner(System.in);

    boolean readValue = false;            //Check if the valid input is received
    boolean shouldAskForNumber = true;    //Need to ask for number again? Case for Enter
    do {
        if (shouldAskForNumber) {
            System.out.print("Enter a number:");
            shouldAskForNumber = false;
        }

        if (scnr.hasNextDouble()) {
            numberOfStudents = scnr.nextDouble();
            readValue = true;
        } else {
            String token = scnr.next();
            if (!"".equals(token.trim())) {   //Check for Enter or space
                shouldAskForNumber = true;
            }
        }
    } while (!readValue);

    System.out.printf("Value read is %.0f\n", numberOfStudents);
    System.out.println("You're outside the loop!");

Update

Understood the following statement in question different way:

But if you hit enter twice, it doesn't loop back. It only displays "Enter a number" once.

The code is set to print "Enter a number" only once if the user hits RETURN/ENTER or enters space character. You may remove the special check and use the code if needed.

James Jithin
  • 8,925
  • 3
  • 34
  • 50
  • That doesn't fix OPs _current_ problem. But it can fix a future problem, though. – Tom Sep 25 '15 at 16:54
  • Your updated answer works for both number and non-number inputs, but does not address OP's concern for multiple enter-presses. Each enter press on a blank line should display "Enter a number:" – CubeJockey Sep 25 '15 at 17:19
  • @Trobbins, got it wrong! Multiple enters has been considered differently in this code. `But if you hit enter twice, it doesn't loop back. It only displays "Enter a number" once.` made me think it should not print again and again. :D – James Jithin Sep 25 '15 at 17:21
  • Is it intended that this code still fails if the user just presses "return" without writing anything to the console? – Tom Sep 25 '15 at 17:38
  • @Tom, `fails` in the sense? – James Jithin Sep 25 '15 at 17:44
  • In the sense, that it does exactly the same what OP currently has and doesn't want: it doesn't print *"Enter a number:"* anymore. It still stucks on the `scnr.hasNextDouble()`. If this is intented, since you read OPs question differently, then you could add that note to the answer (if you like). – Tom Sep 25 '15 at 17:47
1
import java.util.Scanner;

public class Testing {
    public static boolean checkInt(String s)
    {
        try
        {
            Integer.parseInt(s);
            return true;
        } catch (NumberFormatException ex)
        {
            return false;
        }
    }
    public static void main(String[] args) {
        boolean loop = false;
        double numberOfStudents;
        Scanner scnr = new Scanner(System.in);

            String input = "";

            while (!(checkInt(input))) {
                System.out.println("Enter a number");
                input = scnr.nextLine();
            }
            numberOfStudents = Integer.parseInt(input);

        System.out.println("Number of students: " + numberOfStudents );
    }
}

//this code is working fine, if you want you check it out. //In your code your taking another input if the first is an int/double; if the first input is not a number then you have mentioned to take input again..

  • Good code, and certainly cleaner to have the validation in another method. Only criticism I have is you're guaranteeing the test will run a minimum of 2 times: Once when the loop begins, and a second time when the user enters a valid number. Your code would be better if you could have `input` validated just once in that scenario -- only when user inputs a string. – CubeJockey Sep 25 '15 at 18:54
  • @trobbins thanks for your valuable comment. I found your code is very efficient and useful :) – sreenath sirimala Sep 25 '15 at 19:11
0

Use a debugger to see what the code is actually doing. Here's a guide on debugging in Eclipse. After you have finished debugging your code, you will probably know what the problem is.

djechlin
  • 54,898
  • 29
  • 144
  • 264
  • Wrong. `scnr.hasNextDouble()` is not false, it waits until a token was entered and either it is a double or not. When you would test the code, then you would notice that :P – Tom Sep 25 '15 at 16:50
  • OP is wondering why when hitting enter twice in succession, the `System.out.println("Enter a number");` doesn't display multiple times. When I run OP's code, multiple enter keys just print more line breaks. Once the user finally enters a number, the loop exits. – CubeJockey Sep 25 '15 at 16:51
  • 1
    @Trobbins *"Once the user finally enters a number, the loop exits."* Or you get a real problem if you enter an invalid token, like a text, but this is another problem and not part of this question :D. – Tom Sep 25 '15 at 16:53
  • @Tom that's totally false. a "has" method generally does not block. The documentation simply says it returns "true" if next token is a number and "false" otherwise. I couldn't immediately tell by reading the source code which is slightly complicated, so ran locally and am watching an infinite loop on my terminal as we speak. – djechlin Sep 25 '15 at 16:56
  • *"a "has" method generally does not block."* Sorry, but this is nonsense (for `System.in` as the used `InputStream`). You can easily see that by either testing it _correctly_ or by reading the source code. I hope you're not testing with sites like http://ideone.com. If not, which Java Version are you using? – Tom Sep 25 '15 at 17:00
  • @Tom whoops, "hasNext" includes in its documentation "This method may block while waiting for input" as it waits for the next complete token. Unclear to me if OP is inputting full tokens or not. Updated answer accordingly. – djechlin Sep 25 '15 at 17:00
  • "Debug your code" isn't a valid answer. If it was, we'd post it to nearly every question on SO – CubeJockey Sep 25 '15 at 17:05
  • If you want to fundamentally change the content of your answer, (if it has any votes) it's probably better to delete the answer and post a new one, otherwise the votes don't reflect the content, but Trobbins is correct in that this is not currently a valid answer. – Bernhard Barker Sep 25 '15 at 17:05
  • 1
    But I'm still interested in how you have tested OPs code and actually got an infinite loop. Have you entered something or just pressed "return"? – Tom Sep 25 '15 at 17:17
  • @djechlin I don't really agree with that answer (and it's currently sitting at +1, so not exactly mass community agreement), but, ignoring that, this answer is quite different from the example you gave there - here you essentially just said "go debug, here's a link" as opposed to giving debugging advice specific to OP's problem. – Bernhard Barker Sep 25 '15 at 17:31
  • 1
    ... and I strongly disagree that this is actually an issue fully understandable simply by debugging. You may see that `hasNextDouble` doesn't trigger when you enter a new line, but that's still far from understanding the underlying reason why this happens and when exactly it happens. – Bernhard Barker Sep 25 '15 at 17:42
  • 1
    @Dukeling I would you support for that (*"and I strongly disagree that this is actually an issue fully understandable simply by debugging."*). Since djechlin also made a mistake about the behavior of that method (and he is an experienced Java developer (according to the score)), it can be quite hard to understand if you're new either in Java or in using `Scanner`. – Tom Sep 25 '15 at 17:54
0

The following code is working,

boolean loop = true;
    double numberOfStudents;
        Scanner scnr=new Scanner(System.in);
       while(loop) {
            System.out.println("Enter a number");
               if ((scnr.nextLine().trim().isEmpty()) ) {
            loop = true;
        }
            if (scnr.hasNextDouble() ){
                System.out.println("Loop has stopped");
                numberOfStudents = scnr.nextDouble();
                loop = false;
            }
        }
    System.out.println("You're outside the loop!");

The output is,

run:
Enter a number
hj
po
Enter a number
lhf
Enter a number
o
Enter a number
p
Enter a number
a
Enter a number
34
Loop has stopped
You're outside the loop!
Guna
  • 316
  • 5
  • 18
  • 1
    I ran your code, unfortunately it doesn't change OP's problem of multiple "enter" key presses in succession not displaying more "Enter a Number" messages. – CubeJockey Sep 25 '15 at 17:14
  • What Troppins says is correct. OPs problem is that he doesn't enter anything and just presses "return". You can't reproduce that problem by entering letters :P – Tom Sep 25 '15 at 17:15
  • Your code also doesn't work when entering a number on the first attempt. – CubeJockey Sep 25 '15 at 17:16
  • Yeah.. My code has some problems. I'm trying to resolve those. Thank you both for pointing out my mistakes. i'll improve my answer. – Guna Sep 25 '15 at 18:59
  • I'm using both scnr.nextLine() and scnr.hasNextDouble. So when the " if ((scnr.nextLine().trim().isEmpty()) ) " condition fails, one more input is needed by scnr,hasNextDouble() in the next loop.. So i think the only solution is to parse the input to Double like in #Trobbins post. – Guna Sep 25 '15 at 19:16
0

Below code will help you

    boolean loop = true;
    double numberOfStudents;
    Scanner scnr = new Scanner(System.in);
    System.out.print("Enter a number: ");
    String input = scnr.nextLine();
    while(!scnr.hasNextDouble()){
        System.out.print("Enter a number: ");
        try{
            numberOfStudents = Double.parseDouble(input);
            break;
        }catch(NumberFormatException e){
        }
        input = scnr.nextLine();
    }
    System.out.println("You're outside the loop!");
Animesh Kumar Paul
  • 2,033
  • 3
  • 22
  • 36
  • 1
    This code also fails if OP just presses "return", without actually writing something into the console. – Tom Sep 25 '15 at 17:33
  • This code fails when the user enters a string of letters as their first input. Also when pressing enter twice and then entering some letters, "Enter a number: " appears multiple times on the same line. – CubeJockey Sep 25 '15 at 17:44
-1

You have to scan the next line if you want to get more values form the scanner again. The code should be like:

while (loop) {
        System.out.println("Enter a number");
        if(!(scnr.nextLine().trim().isEmpty())){
            if (scnr.hasNextDouble() ){
                System.out.println("Loop has stopped");
                numberOfStudents = scnr.nextDouble();
                loop = false;
            }
        }
    }
Alberto Garrido
  • 485
  • 2
  • 6
  • 14
  • 3
    Please don't do this. You're throwing away a line of input in your first if-statement, regardless of what that line actually contains. And don't mix `nextLine` with other `next...` functions - they don't interact well. – Bernhard Barker Sep 25 '15 at 17:02
  • 2
    Going along with what @Dukeling mentioned with mixing `nextLine` and other `next` functions, here is an [SO post explaining how this could break your expectations](http://stackoverflow.com/questions/13102045/skipping-nextline-after-using-next-nextint-or-other-nextfoo-methods) – CubeJockey Sep 25 '15 at 17:24
  • 1
    Yes, you're both right. I did it too fast only to show that he was missing a scan in his logic. I should pay more attention. – Alberto Garrido Sep 25 '15 at 18:37