简体   繁体   中英

How-to validate user input when using scanner for input gathering

Description

What I am aiming to do is request user to provide an input only to those entries which triggered an exception excluding those input requests which have been satisfactory

Example

Note : input is an instance of a Scanner

public Fluid addFluid() {
    do{
        try{
            System.out.println("Please enter fluids ID: "); 
            f.setFluidID(input.next());
            System.out.println("Please enter fluids molecular weight: ");   
            f.setMolecularWeight(input.nextDouble()); 
            System.out.println("Please enter fluids temperature: ");            
            f.setTemperature(input.nextDouble());
            error = false;
        }
        catch(InputMismatchException e){
            System.out.println("Error! Please provide the right input.");
           // if exception happens on input for setMolecularWeight(input.nextDouble()); skip print statement for fluids ID and f.setFluidID(input.next());
        }
    }
    while(error != false);
    getFluid().add(f);
    System.out.println(getFluid());
    return f;
}

Output

Please enter fluids ID: 
propane
Please enter fluids molecular weight: 
a
Error! Please provide the right input.
Please enter fluids ID:                // how to exclude this print statement
Please enter fluids molecular weight: 

Would there be a way how to do this using an if / else structure. I would want to avoid doing try / catch for every input operator. Many thanks in advance.

Short answer:

You'll need clear the buffer on the Scanner after the call to nextDouble() , since your InputStream will contain a newline \\n .

Adding input.next(); or input.nextLine(); to the end of your catch blocks should work to skip that extra \\n .

(See java.util.Scanner : why my nextDouble() does not prompt? )

Explanation:

  • Even though nextDouble blocks execution until the user enters a newline \\n , it only returns characters from Scanner 's buffer that are valid characters (characters that will parse correctly to a double ). This means
  • if you enter input that doesn't parse to a double , those invalid characters are still sitting in the buffer. When you attempt to read the nextDouble again, it will just repeat the same process on the existing input, resulting in the infinite loop.
  • Therefore, you'll need to "clear" the buffer before continuing. Since there doesn't seem to be a method for this, you'll just need to advance the Scanner to the end of the buffer. In this case, input.next(); will suffice.

(Credits to user jonhopkins for the code I shamelessly grabbed from his answer )

System.out.println("Please enter fluids ID: ");
while (true) {
    try {
        f.setFluidID(input.next());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
        input.next();
    }
}

System.out.println("Please enter fluids molecular weight: ");
while (true) {
    try {
        f.setMolecularWeight(input.nextDouble());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
        input.next();
    }
}

System.out.println("Please enter fluids temperature: ");
while (true) {
    try {
        f.setTemperature(input.nextDouble());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
        input.next();
    }
}

NOTE: You may even need an extra input.next() call before you read the 2nd and 3rd inputs (I haven't tested this).

Simply place it outside your loop:

public Fluid addFluid() {
    System.out.println("Please enter fluids ID: "); 
    f.setFluidID(input.next());

    do{
        try{    
            System.out.println("Please enter fluids molecular weight: ");   
            f.setMolecularWeight(input.nextDouble()); 
            System.out.println("Please enter fluids temperature: ");            
            f.setTemperature(input.nextDouble());
            error = false;
        }
        catch(InputMismatchException e){
            System.out.println("Error! Please provide the right input.");
           // if exception happens on input for setMolecularWeight(input.nextDouble()); skip print statement for fluids ID and f.setFluidID(input.next());
        }
    }
    while(error != false);
    getFluid().add(f);
    System.out.println(getFluid());
    return f;
}

Now it will only print it once while the other input can be repeated. If you want to check for individual problems with the molecular weight and fluids temperature, you'll have to repeat the try-catch.

Not pretty but should work:

public Fluid addFluid() {
    boolean alreadyAnswered1 = false;
    boolean alreadyAnswered2 = false;
    boolean alreadyAnswered3 = false;
    do{
        try{
            if (!alreadyAnswered1) {
                System.out.println("Please enter fluids ID: ");
                 f.setFluidID(input.next());
                 alreadyAnswered1 = true;
            }
            if (!alreadyAnswered2) {
                System.out.println("Please enter fluids molecular weight: ");
                f.setMolecularWeight(input.nextDouble());
                alreadyAnswered2 = true;
            }
            if (!alreadyAnswered3) {
                System.out.println("Please enter fluids temperature: ");
                f.setTemperature(input.nextDouble());
                alreadyAnswered3 = true;
            }
            error = false;
        }
        catch(InputMismatchException e){
            System.out.println("Error! Please provide the right input.");
           // if exception happens on input for setMolecularWeight(input.nextDouble()); skip print statement for fluids ID and f.setFluidID(input.next());
        }
    }
    while(error != false);
    getFluid().add(f);
    System.out.println(getFluid());
    return f;
}

It looks to me like you want to repeat the request for input for whichever ones where an exception is thrown. I would just use a few smaller loops, each with their own separate try-catch blocks.

System.out.println("Please enter fluids ID: ");
while (true) {
    try {
        f.setFluidID(input.next());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
    }
}

System.out.println("Please enter fluids molecular weight: ");
while (true) {
    try {
        f.setMolecularWeight(input.nextDouble());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
    }
}

System.out.println("Please enter fluids temperature: ");
while (true) {
    try {
        f.setTemperature(input.nextDouble());
        break; // break out of the current loop
    } catch (InputMismatchException e) {
        System.out.println("Error! Please provide the right input.");
    }
}

This will cause the program to loop for each input until no exception is thrown for that input. It also removes the need for an outer loop that keeps going until error == false . If you want the input prompts to be displayed again after the error message, simply put the prompts inside their respective while loops.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM