Stop infinite Loop when handling invalid user input - Java [duplicate] - java

This question already has answers here:
How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner
(5 answers)
Closed 2 years ago.
I'm fairly new to programming and I'm having trouble with my program continuously looping when I try to handle a InputMisMatch exception.
I have a menu which takes in user input and then uses a switch statement to deal with the input. I am trying to make my program handle two exceptions. First is making sure that the input is actually an integer and secondly make sure the integer is within the range for the menu. I used the NextInt() method inside a try block. Inside the try block is the switch statement which uses the default case to deal with the input not being in range
However the catch block for when the user types in an input other than an integer keeps looping over and over. It seems I have not updated the user input inside the loop somewhere but I am confused as to where to update it.
For now, I'm not concerned with what is in the switch cases (although I want to implement the same looping feature inside of them as well), It's just the logic for the outer loop.
Here's my code:
Any guidance would be much appreciated. Thanks!
public class Main {
// set up scanner for user input
public static Scanner keyboard = new Scanner(System.in);
public static void main(String[] args) {
// welcome message
welcome();
//declare user choice variables
int menuSelection;
int discSelection;
boolean isInputValid = true ;
do { // keep looping until user input is valid
try {
/*
We can expect an error from user input
1. Input is not an integer
2. Input is not in range
*/
isInputValid = true;
displayMainMenu();
menuSelection = keyboard.nextInt();
System.out.println(); //print new line
//Menu Logic
switch (menuSelection) {
case 0: { // Exit Application
break;
}
case 1: { // Search
searchDiscMenu(); //Display the search menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.searchMusic()");
} else if (discSelection == 2) {
System.out.println("Disc.Game.searchGame()");
}
break;
}
case 2: { // Add
addDiscMenu(); //Display add menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.addMusic()");
} else if (discSelection == 2) {
System.out.println("Disc.Game.addGame();");
}
break;
}
case 3: { // Remove
removeDiscMenu(); //Display remove menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.removeMusic();");
} else if (discSelection == 2) {
System.out.println("Disc.Game.removeGame();");
}
break;
}
case 4: { // View
viewDiscMenu(); //Display view menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.viewMusic();");
} else if (discSelection == 2) {
System.out.println("Disc.Music.viewMusic();");
}
break;
}
case 5: { // Sort
sortDiscMenu(); //Display sort menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.viewMusic();");
} else if (discSelection == 2) {
System.out.println("Disc.Music.viewMusic();");
}
break;
}
case 6: { // Write
writeDiscMenu(); //Display write menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.viewMusic();");
} else if (discSelection == 2) {
System.out.println("Disc.Game.writeGameFile();");
}
break;
}
case 7: { // Read
readDiscMenu(); //Display read menu
discSelection = keyboard.nextInt(); // get user choice
if (discSelection == 1) {
System.out.println("Disc.Music.readMusicFile();");
} else if (discSelection == 2) {
System.out.println("Disc.Game.readGameFile();");
}
break;
}
default: { // Handle exception
isInputValid = false;
System.out.println("Error: Selection Not In Range"); // If the input is an int but not in range
break;
}
}
} catch (InputMismatchException e) { // Handles user typing in a char, double etc. instead of int
isInputValid = false;
System.out.println("Error: Unrecognised Input");
}
} while (!isInputValid);
// Exit application safely
System.out.println("Finished"); // temporary message
}

This can happen since the nextInt() doesn't consume the new line character inserted in the buffer when pressed enter to type something in the console.
To overcome this you can add keyboard.nextLine() to the catch block so you can consume that new line character inserted in the buffer and clear it to the next input.
As others said you should wrap your input hadling in a method since you have louds of nextInt that won't be catched by your InputMismatchException. Said method should call the nextInt() catch the exception if needed and clear the buffer for new line characteres with the nextLine() if not returns the input by the user.
That way you're guarantee that you will always catching that error.

It would be better if you use a method like this to check your input :
public int rangeInt(int lower_boundary, int upper_boundary) {
int inp = -1;
try {
Scanner in = new Scanner(System.in);
inp = in.nextInt();
in.nextLine();
if (inp < lower_boundary || inp > upper_boundary) {
throw new InputMismatchException();
}
} catch (InputMismatchException e) {
System.err.println("Please enter integer between " + lower_boundary + " and " + upper_boundary);
inp = rangeInt(lower_boundary, upper_boundary);
}
return inp;
}
This method handles InputMismatchException and returns an integer between the to ints you pass

Related

Handling InputMismatchException in a While-Loop

So I have a while-loop where you have 3 options to choose from and you choose them by inserting a number on standard input using a scanner, my code is like this:
int option;
String request;
Scanner input2 = new Scanner(System.in);
System.out.println("Choose an option:\n" + "1-Get camera information\n" + "2-Submit Data\n"
+ "3-Exit");
while(true){
try {
option = input2.nextInt();
if (option == 1) {
System.out.println("Camera name:");
request = input2.nextLine();
while (request.length() < 3 || request.length() > 15) {
System.out.println("Name has to be between 3 and 15 characters, insert a new one:");
request = input2.nextLine();
}
CamInfoRequest info_request = CamInfoRequest.newBuilder().setName(request).build();
if (stub.camInfo(info_request).getReturn() != 0) {
System.out.println("Camera does not exist");
} else {
System.out.println(stub.camInfo(info_request).getLatitude() + " " + stub.camInfo(info_request).getLongitude());
}
} else if (option == 2) {
System.out.println("submit");
} else if(option ==3){
break;
} else{
System.out.println("Invalid option.");
}
}catch(InputMismatchException e){
System.out.println("Invalid input");
}
}
So the way this is the code enters in an infinite loop when it catches the exception where it keeps printing "Invalid input", I tried using input2.next() at the catch but then he waits for another input I don't want, I can't use input2.close() either. What can I do?
I can't use input2.close() either.
You should never close the Scanner instance for System.in as it also closes the System.in.
I tried using input2.next() at the catch but then he waits for another
input I don't want
Use Scanner::nextLine instead of Scanner::next, Scanner::nextInt etc. Check Scanner is skipping nextLine() after using next() or nextFoo()? to learn why.
Also, try to use do...while wherever you need to ask the user to enter the data again in case of an invalid entry.
Given below is a sample code incorporating these points:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int option;
boolean valid;
Scanner input2 = new Scanner(System.in);
do {
valid = true;
System.out.println("Choose an option:\n" + "1-Get camera information\n" + "2-Submit Data\n" + "3-Exit");
try {
option = Integer.parseInt(input2.nextLine());
if (option < 1 || option > 3) {
throw new IllegalArgumentException();
}
// ...Place here the rest of code (which is based on the value of option)
} catch (IllegalArgumentException e) {
System.out.println("This is an invalid entry. Please try again.");
valid = false;
}
} while (!valid);
}
}
A sample run:
Choose an option:
1-Get camera information
2-Submit Data
3-Exit
abc
This is an invalid entry. Please try again.
Choose an option:
1-Get camera information
2-Submit Data
3-Exit
6
This is an invalid entry. Please try again.
Choose an option:
1-Get camera information
2-Submit Data
3-Exit
2
Feel free to comment in case of any further doubt/issue.
Just Put the Scanner statement inside your try block
while (true) {
try {
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();
if (option == 1) {

What return statement should I utilize in order to use a Menu that throws an exception for non integer values?

I am working on a to do list and am currently stuck making a menu. The menu receives input from the user of the numbers 1-6 and carries out a specific task associated with that number(int). That's the perfect world scenario, so I need the menu to be able to take non integer values and not be bricked as well as display an error message to the user. I think I have created an efficient way of asking the user for integers without bricking the program but I cannot determine what my return statement should be in order to utilize the method in the main. I'll use it in a switch statement like this:
while (true) {
switch (getMenuOption()) {
case 1:
etc
This is the current method that I have for the getMenuOption. What return statement should I use, or is there a more efficient way to carry this out?
package project1_martinez_adriel;
import java.util.Scanner;
public class getMenuOption {
public static int getMenuOption() {
Scanner input = new Scanner(System.in);
System.out.println(" 1. Create a new item \n 2. Mark an item as in progress \n 3. Mark an item as completed \n 4. List all to do items \n 5. Remove completed items \n 6. Exit \n What would you like to do? \n ");
String value = input.nextLine();
int num;
try {
num = Integer.parseInt(value);
if (!(num == 1 || num == 2 || num == 3 || num == 4 || num == 5 || num == 6)) {
System.out.println("ERROR! Invalid choice! \nPlease enter a valid choice BETWEEN 1 & 6: ");
}else if (num == 6){
System.exit(0);
}
} catch (NumberFormatException e) {
System.out.println("ERROR! Please enter a valid INTEGER between 1 & 6.");
}
return //What do I put here!?
}
how about cleaning it up to be
if (num < 1 || num > 6) {
System.out.println("ERROR! Invalid choice!...");
}
then later
return num;
The code in your switch statement should process the options between 1 && 6 including 6 being System.exit (0);
I would even have the error messages in the switch default block
edit
num should also be initialized with a value, something like
int num = -1;
So after some clean up, frustration, & long hours I have come up with this, including the switch statements:
Scanner input = new Scanner(System.in);
boolean validInput = false;
do {
System.out.print("Enter an integer: ");
int num;
try {
num = input.nextInt();
switch (num) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6: // cascading case statement example
validInput = true;
break;
default:
System.out.println("ERROR! Please enter a valid choice BETWEEN 1 & 6 (inclusive): ");
num = input.nextInt();
break;
}
} catch (Exception e) {
/* input.next() to move the Scanner forward. */
System.out.println(input.next() + " was not valid input.");
System.out.println("ERROR! Please enter a valid INTEGER between 1 & 6.");
}
} while (!validInput);
input.close();
}
}

How to make a try block within a loop?

I just learned about the 'try' statement in Java, and what I'm trying to do is to have this input loop until the user's input is both an integer and a positive one.
This is my code so far:
int scanning () {
Scanner scan = new Scanner(System.in);
int input = 0;
boolean loop = false;
do {
try {
System.out.print("Amount: ");
input = scan.nextInt();
if (input < 0) {
System.out.println("Error. Invalid amount entered.");
loop = true;
}
} catch (Exception e) {
System.out.println("Error: Invalid input");
loop = true;
}
} while (loop);
return input;
}
However it goes through an infinite loop when the user inputs an invalid integer, printing the error message over and over. The expected outcome is to keep asking the user for a valid input.
This code will help you to be in infinite loop and also throw a exception when input is a -ve integer.
The exception handling in java is one of the powerful mechanism to handle the runtime errors so that normal flow of the application can be maintained.
Most of the times when we are developing an application in java, we often feel a need to create and throw our own exceptions.So first create a user defined exception AmountException.
public class AmountException extends Exception {
private static final long serialVersionUID = 1L;
public AmountException() {
// TODO Auto-generated constructor stub
System.out.println("Error. Invalid amount entered");
}
}
And now edit your scanning() to this :
int scanning () {
Scanner scan = new Scanner(System.in);
int input = 0;
boolean loop = false;
do {
try {
System.out.print("Amount: ");
input = scan.nextInt();
if (input < 0) {
loop = true;
throw new AmountException();
} else {
loop = false;
}
} catch (AmountException e) {
}
} while (loop);
return input;
}
Reset the value of loop variable in the do-while loop before each time just before checking the condition.
do {
try {
System.out.print("Amount: ");
input = scan.nextInt();
loop = false; // Reset the variable here.
if (input < 0) {
System.out.println("Error. Invalid amount entered.");
loop = true;
}
} catch (Exception e) {
System.out.println("Error: Invalid input");
scan.next(); // This is to consume the new line character from the previous wrong input.
loop = true;
}
} while (loop);
From you code, Change loop to false and when the valid input is given, it will terminate the while loop
boolean loop = false;
do {
try {
loop = false;
System.out.print("Amount: ");
input = scan.nextInt();
if (input < 0) {
System.out.println("Error. Invalid amount entered.");
loop = true;
}
} catch (Exception e) {
System.out.println("Error: Invalid input");
loop = true;
}
Add an else block after if, otherwise, loop will always stay true if the first input is invalid.
if (input < 0) {
System.out.println("Error. Invalid amount entered.");
loop = true;
} else {
loop = false;
}

How would I create a "infinite" loops until the user decides to call it quits?

I'm having a slight problem.
I have a menu asking to:
reroll
get val
show max
show min
when the user chooses an option I want it to do one of them THEN re ask the menu in a sort of inifinite loop:
code:
import java.io.InputStream;
import java.util.Scanner;
class RecordDice {
public static void main(String[] args){
int dSides, Sides, Choice;
int max, min;
Scanner s = new Scanner(System.in);
Scanner c = new Scanner(System.in);
System.out.println("How many sides should the dice have?");
Sides = s.nextInt();
if(Sides == 4 || Sides == 6 || Sides == 12 || Sides == 20 || Sides == 100){
System.out.println("Please make a choice:\n" +
"1 - reroll the dice\n" +
"2 - get the value\n" +
"3 - show the maximum\n" +
"4 - show the minimum");
} else {
System.exit(-1);
}
Dice2 d = new Dice2(Sides);
int Choice = c.nextInt();
int Value = d.getValue();
switch(Choice){
case 1:
System.out.println();
d.reroll();
break;
case 2:
System.out.println("The current value is " + Value);
break;
case 3:
System.out.println("The maximum is " );
break;
case 4:
System.out.println("The minimun is ");
break;
}
}
}
Would putting the menu in a method and just calling the method every time a option is picked?
You can use a while loop to keep displaying it.
boolean keepGoing = true;
While(keepGoing)
{
//your code
}
Then to end it ask the user if they want to end it an set the boolean to false.
Add "5 - quit" to your menu.
Create a boolean, something like exit, initialized to false.
Add case 5: exit = true; break;
Then wrap the whole thing in while(!exit)
boolean exit = false;
while(!exit) {
//all the code you already have, starting with:
System.out.println("How many sides should the dice have?");
//and ending with the switch statement
//Plus the addition to the menu and addition to the switch statement
}
Ordinarily, I would do something like:
while(true) {
//do stuff
if(someExitCondition) {
break;
}
}
But seeing how as you're handling your user input with a switch statement, my above suggested method seems to be the cleanest way of handling it in this scenario.
Wrap it all in a do-while loop.
boolean userWantsToQuit = false;
do {
// code
// evaluate userWantsToQuit…
} while (!userWantsToQuit);
boolean keepGoing=true;
while(keepGoing)
{
//user input
if(user input to exit)
{
keepGoing=false;
}
}
or
while(true)
{
//user input
if(user input to exit)
{
break;
}
}
Assuming selection of dice sides you will allow only once, put code below that in do while loop.
You may prompt user "Do you wish to continue" after your switch block.
Get that value scanned
Condition in while loop will be something list while("YES".equals(userInput)).. assuming user will input YES or NO strings.

How do I gracefully make a java.util.Scanner wait for input again?

I have the following part of a program, which emulates a very basic menu.
while (true) {
int selection;
try {
selection = scanner.nextInt();
} catch (Exception e) {
selection = -1;
}
switch (selection) {
case 0:
System.exit(0);
default:
System.out.println("No valid selection!");
}
}
Now, whenever I enter not an integer, the selection is set to -1 and the error message is printed. However, the loop continues endlessly, with the Scanner not waiting for any input.
How do I tell it to wait again? How do I fail more gracefully on malformed user input here?
When a Scanner fails to read something, the offending data is not removed from the stream, which means any subsequent read will fail again until the data is cleared.
To fix this, you could, on failure, just read something and ignore the result:
try {
selection = scanner.nextInt();
} catch (Exception e) {
selection = -1;
scanner.next(); // discard the input
}
Not sure throwing and catching an exception is relevant in your case.
Try:
boolean isValid = false;
int selection;
while(!isValid) {
isValid = scanner.hasNextInt();
if(!isValid) {
System.out.println("No valid selection!");
scanner.next();
} else {
selection = scanner.nextInt();
}
}
if(selection == 0) {
System.exit(0);
}
Make some user input exit out/break the while loop. Like if a user enters "Exit" while loop stops.
Besides that you can do something like:
catch (Exception e) {
selection = -1;
}
switch (selection) {
case 0:
System.exit(0);
default:
System.out.println("No valid selection!");
System.out.println("Try again!");
selection = scanner.nextInt();
}

Categories