Marina Alenskaja
Marina Alenskaja

Reputation: 53

Having trouble with validation: infinite loop occurs even though the logic seems fine

I am working on this 'restaurant' program, that takes two inputs: the bill amount and a satisfactionlevel from 1 to 3. I have tried to validate each output using the hasNextDouble(), but for some reason when i run the program the else statement in the first if statement runs infinitly. Can someone please take a look at this?

package tips;

import java.util.Scanner;

public class Tips {

public static void main(String[] args) {
    /* Ask for the diners’ satisfaction level using these ratings: 
    1 = Totally satisfied, 2 = Satisfied, 3 = Dissatisfied.
    If the diner is totally satisfied, calculate a 20 percent tip.
    If the diner is satisfied, calculate a 15 percent tip.
    If the diner is dissatisfied, calculate a 10 percent tip.
    Report the satisfaction level and tip in dollars and cents.*/

    Scanner in = new Scanner(System.in);

    boolean isDouble = false;
    boolean isInt = false;

    TipsCalculator tips = new TipsCalculator();

    while (!isDouble && !isInt) {
          System.out.print("Please enter the bill amount: ");
          //Checks if the input is a double.
          if(in.hasNextDouble()) {
              tips.setBill(in.nextDouble());
              isDouble = true;
          } else {
              System.out.println("The value entered is not a valid amount.");
              continue;
          }

          System.out.println("Please enter your satisfaction level: \n1 = Totally Satisfied.\n2 = Satisfied.\n3 = Dissatisfied.");
          //Checks if the input is an integer.
          if(in.hasNextInt()) {
              tips.setSatisfactionLevel(in.nextInt());
              isInt = true;
              //Prints different outputs depending on the satisfaction level.
              if (tips.getSatisfactionLevel() == 1) {
                  System.out.println("You are totally satisfied! :-)" + 
                          ". \n" + 
                          "Your tip amount is: " + 
                          tips.calculateTips());
              } else if (tips.getSatisfactionLevel() == 2){
                  System.out.println("You are satisfied! :-)" + 
                          ". \n" + 
                          "Your tip amount is: " + 
                          tips.calculateTips());
              } else if (tips.getSatisfactionLevel() == 3) {
                  System.out.println("You are dissatisfied! :-(" + 
                          ". \n" + 
                          "Your tip amount is: " + 
                          tips.calculateTips());
              } else {
                  //Error if the level is not from 1 to 3.
                  System.out.println("The value entered is not between 1 and 3");
              }
          } else {
              System.out.println("The value entered is not between 1 and 3");
              continue;
          }
    } in.close();

}

}

Upvotes: 1

Views: 125

Answers (3)

Ravindra Devadiga
Ravindra Devadiga

Reputation: 692

Reason for infinite loop is: hasNextDouble method in Scanner class calls hasNext method internally. It has written like this

public boolean hasNext(Pattern pattern) {
        ensureOpen();
        if (pattern == null)
            throw new NullPointerException();
        hasNextPattern = null;
        saveState();

        while (true) {
            if (getCompleteTokenInBuffer(pattern) != null) {
                matchValid = true;
                cacheResult();
                return revertState(true);
            }
            if (needInput)
                readInput();
            else
                return revertState(false);
        }
    }

In the above method, getCompleteTokenInBuffer method call is the real culprit. This getCompleteTokenInBuffer can return following 3 possibilities

/*
 * 1. valid string means it was found
 * 2. null with needInput=false means we won't ever find it
 * 3. null with needInput=true means try again after readInput
 */

In hasNext mthod, whenever we first enter non double value, we will be able to read data and getCompleteTokenInBuffer returns null and will also set needInput=false for the first time. But, for the second time, hasNext method will return with value false as needInput=false condition will be true.

This needInput = false condition will remain true for the subsequent hasNextDouble method call. Because of this we were not able to read any data and this was causing infinite loop.

Upvotes: 0

Michael Gantman
Michael Gantman

Reputation: 7808

Don't read input as double and int. read it as Strings and then parse it to Double or Integer in your code. Use method valueOf(String) in classes Integer and Double. to parse your Strings

Upvotes: 1

Rahman
Rahman

Reputation: 3795

isDoubl & isInt both are false so !isDouble && !isInt will be always true. This is the root cause behind infinite loop

Upvotes: 2

Related Questions