views:

680

answers:

4

Hey there! I'm trying to do some data input validation but I haven't been able to figure it out. I'm getting an infinite while loop in when I try to validate if the first character entered is a letter. . . .

Thanks for your help!

public class methods
{
    public static void main(String args[]) throws IOException
    {
        String input ="";
        int qoh=0;
        boolean error=true;

        Scanner keyboard = new Scanner (System.in);

        //while (error)
        //{
            //error=true;

        while (error==true)
        {
           System.out.print("\nEnter Quantity on Hand: ");
           input = keyboard.nextLine();

           if (input.length() <1)
           {
               System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
               error=true;
               System.out.println(qoh);
               System.out.println(input);
            }
            else
            {
                error=false;
            }
        }

        error = true;

        while (error==true)
        {
            if (Character.isLetter(input.charAt(0)))
            {
                System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
                error=true;
                System.out.println(qoh);
                System.out.println(input);
             }
             else
             {
                 qoh = Integer.parseInt(input);
                 error=false;
              }
          }
      }
  }
+2  A: 

You don't have an input = keyboard.nextLine(); in your second while loop.

You could refactor your code to only ask for new input when there is an error. So right after the sysout of 'ERROR...'

Extra: I would actually do this different. The 'error = true' at the beginning is a bit confusing, because there might not be an error.

You could for example write a method called tryProcessLine, which reads the input and returns true if ok and false if there was an error, and than just do something like while(!tryProcessLine()){ }

Working example below:

import java.io.IOException;
import java.util.Scanner;

public class Methods {

  private static int qoh;

  public static void main(String args[]) throws IOException {

    while (!tryProcessLine()) {
        System.out.println("error... Trying again");
    }

    System.out.println("succeeded! Result: " + qoh);

  }

  public static boolean tryProcessLine() {

    String input = "";

    Scanner keyboard = new Scanner(System.in);

    System.out.print("\nEnter Quantity on Hand: ");

    input = keyboard.nextLine();

    try {
        qoh = Integer.valueOf(input);

        if (qoh < 0 || qoh > 500) {
          System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
          return false;
        } else {
          return true;
        }
    } catch (NumberFormatException e) {
        System.out.println("\n**ERROR06** - Quantity on hand must be numeric");
        return false;
    }
  }
}
Fortega
-1: This is not the cause of the infinite loop. The first loop is designed to read the first non-empty line whereas I presume the second loop is supposed to check this line only contains numeric characters (rather than read another line of input).
Adamski
I guess he wants to get a new input when the error in the second loop happens. Otherwise the second loop should not be a loop. Because now when there is an 'error' in the second loop, no new input is requested, and 'error==true' will always be true...
Fortega
My guess is that he wants to read the first non-empty line of input and attempt to parse it into an integer. I don't think the OP requires two loops at all.
Adamski
If that is the case, the second while loop should just be an if statement...
Fortega
+1  A: 

The infinite loop occurs because the second while loop is repeatedly checking whether the first character in the String (input.charAt(0)) is a letter. Assuming that the result from this check is true the loop will never terminate.

Your code could be simplified to something like:

Integer qty = null;

while (scanner.hasNext() && qty == null) {
  String line = scanner.next();
  try {
    qty = Integer.parseInt(line);
  } catch(NumberFormatException ex) {
    System.err.println("Warning: Ignored non-integer value: " + line);
  }
}

if (qty == null) {
  System.err.println("Warning: No quantity specified.");
}
Adamski
A: 

If it is a character, you're allowing error to still = true, which is causing that loop to continue forever, you're not ever going back to the beginning and reading another line.

Here is some code that does what you want and is structured a little better.

public class ScanInfo {

  Scanner keyboard = new Scanner(System.in);

  public ScanInfo(){
    String line = getLineFromConsole();
    while(null != line && !"quit".equals(line)){
      if(isValidInput(line)){
        int validNumber = Integer.parseInt(line);
        System.out.println("I recieved valid input: "+validNumber);
      }else{
        System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
      }
      line = getLineFromConsole();
    }

  }

  private boolean isValidInput(String line){
    //basic sanity
    if(null == line || line.length() < 1){
      return false;
    }


    try {
      int number = Integer.parseInt(line);

      return (number >= 0 && number <= 500);

    } catch (NumberFormatException e) {
      return false;
    }

  }


  public static void main(String[] args) {
    new ScanInfo();

  }

  public String getLineFromConsole(){
    System.out.print("\nEnter Quantity on Hand: ");
    return keyboard.nextLine();

  }

}
Kylar
Why do you parse the input into an integer twice?
Adamski
"quit" != line should be !"quit".equals(line)
Fortega
I parse the integer twice because I'm lazy and encapsulated it wrong. Fortega: made your change.
Kylar
+1  A: 

The problem is in this section:

                        while (error==true)
                        {
                            if (Character.isLetter(input.charAt(0)))
                            {
                                System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
                                error=true;
                                System.out.println(qoh);
                                System.out.println(input);
                            }
                            else
                            {
                                qoh = Integer.parseInt(input);
                                error=false;
                            }
                        }

Once you have a letter in the first position, this loop can never terminate. It checks whether a letter is in the first position (it is), prints it, and repeats. Try changing to:

                            while (error==true)
                            {
                                if (Character.isLetter(input.charAt(0)))
                                {
                                    System.out.println("\n**ERROR06** - Quantity on hand must be between 0 and 500");
                                    error=false;

                                    ...

Also, a couple of other things:

while (error == true) can be shortened to while(error).

Also, Integer.parseInt will throw a NumberFormatException if the input is not an integer - you need to catch and handle this.

Also, why do you need the second loop at all? It seems like it is only supposed to validate the input - if so, you can move this logic into the first loop and eliminate the second one. Only use loops for things that should happen repeatedly (like the user entering input data). There is no need to check the same input repeatedly.

danben