I have copied the exact same code from another program. Whenever inputting deliberate incorrect results the InputMismatchException still occurs and the program crashes.
import java.util.*;
public class Runner{
public static void main (String args[]){
Scanner sc = new Scanner(System.in);
sc.useDelimiter("\n");
Fixture f = new Fixture();
boolean inputValid = false;
int choice = 0;
do{
do {
System.out.println("\f\t\tFootball Database");
System.out.println("A utility to help make footballing events easier to manage.");
System.out.println("");
System.out.println("\t> Press 1 to manage players ");
System.out.println("\t> Press 2 to manage teams");
System.out.println("\t> Press 3 to manage coaches");
System.out.println("\t> Press 4 to manage fixtures");
System.out.println("\t> Press 5 to save database to file");
System.out.println("\t> Press 6 to load database from file");
System.out.println("\t> Press 7 to terminate program");
System.out.println("");
System.out.println("");
System.out.println("©Thomas Camilleri 2017");
try{
choice = sc.nextInt();
inputValid = true;
}catch(InputMismatchException e){
System.out.println("Invalid input");
inputValid = false;
sc.nextInt();
sc.nextInt();
}
}while(inputValid == false);
Here is the salient part of your code:
try {
choice = sc.nextInt(); // NOT HERE
inputValid = true;
} catch(InputMismatchException e){
System.out.println("Invalid input");
inputValid = false;
sc.nextInt(); // HERE
sc.nextInt();
}
If you look at the stacktrace that you got, and look at the line numbers, you will see that the line in your code where the exception happens is the one I have tagged with // HERE.
(Compile and run the original program and look at the stacktrace to see what I mean. Compare the line numbers in the stack trace with the source code.)
As you can see, that line is NOT in the try { ... } block. It is in the exception handler block.
What has happened is that you have caught the exception that was thrown at the line tagged // NOT HERE, and then you have called sc.nextInt() again (at // HERE). The second call has simply attempted to read the same input characters again.
The behavior of the nextInt method is as follows:
get characters sufficient to form a token
attempt to convert the entire token into an integer (using base-10 integer syntax)
if the conversion succeeds, return the converted integer
if the conversion fails, put all of the characters back and then throw an exception.
I strongly encourage you to carefully read the javadocs for the Scanner class so that you understand what the methods you are using actually do.
So ... as you see ... if you just call nextInt() after a failed nextInt() call, you just get the same failure repeated.
The reason that second exception is not caught is that it has not been thrown within the try { ... } block.
Solution: Instead of calling nextInt() in the handler, you should call a method that is going to just discard the rubbish. In this case, the most sensible thing to do is to throw away everything up to the next end-of-line.
Hint #1: the nextLine() gets everything up to the next end-of-line. Read the javadocs for that method too.
Hint #2: if you understand what I said, you will know where to put your modification.
Try like:
choice = Integer.parseInt(sc.nextLine());
and your program will like this:
try (Scanner sc = new Scanner(System.in)) {
sc.useDelimiter("\n");
// Fixture f = new Fixture();
boolean inputValid = false;
int choice = 0;
// removed outer do..while(); loop
do {
System.out.println("\f\t\tFootball Database");
System.out.println("A utility to help make footballing events easier to manage.");
System.out.println("");
System.out.println("\t> Press 1 to manage players ");
System.out.println("\t> Press 2 to manage teams");
System.out.println("\t> Press 3 to manage coaches");
System.out.println("\t> Press 4 to manage fixtures");
System.out.println("\t> Press 5 to save database to file");
System.out.println("\t> Press 6 to load database from file");
System.out.println("\t> Press 7 to terminate program");
System.out.println("");
System.out.print("Enter your choice : ");
try{
// Always use nextLine() if you mix String and basic Datatype
choice = Integer.parseInt(sc.nextLine());
inputValid = true;
}catch(NumberFormatException e){
System.out.println("Invalid input");
inputValid = false;
// Removed unnecessary two sc.nextInput() lines
}
}while(inputValid == false);
System.out.println("choice is : " + choice);
}
Related
I want to make a simple loop that will only end when user chooses to quit. I am having problems with Scanner and I can't really pinpoint it but I think it might be the .close() function. I've tried to put .close() almost everywhere, but the error still persists. I also tried to remove the .close() but what happens is it keeps looping even though I chose Quit.
import java.util.Scanner;
public class CipherServiceTest {
static String keysquare;
public static void main(String args[]) {
System.setProperty("key.square","alpha"); //default key.square
keysquare = System.getProperty("key.square");
WhatToDo();
}
static void WhatToDo() {
int choice=0, datatype=0;
Scanner scan = new Scanner(System.in);
CipherServiceImpl cs = new CipherServiceImpl();
System.out.println("1. Encrypt a file");
System.out.println("2. Decrypt a file");
System.out.println("3. Quit");
System.out.print("What do you want to do(1/2/3): ");
choice = scan.nextInt();
while(choice != 3) {
System.out.println("1. Alpha");
System.out.println("2. Binary");
System.out.print("Choose data type(1/2): ");
datatype = scan.nextInt();
if (choice==1) {
if (datatype == 1) {
System.setProperty("key.square","alpha"); //default key.square
keysquare = System.getProperty("key.square");
cs.encrypt( );
}
else if (datatype ==2) {
System.setProperty("key.square","binary");
keysquare = System.getProperty("key.square");
cs.encrypt();
}
else {
System.out.println("Wrong Input");
//main(null);
}
}
else if (choice==2) {
if (datatype == 1) {
System.setProperty("key.square","alpha"); //default key.square
keysquare = System.getProperty("key.square");
cs.decrypt();
}
else if (datatype == 2) {
System.setProperty("key.square","binary");
keysquare = System.getProperty("key.square");
cs.decrypt();
}
else {
System.out.println("Wrong Input");
//main(null);
}
}
else{
System.out.println("Wrong Input");
//main(null);
}
//scan1.close();
main(null);
}
scan.close();
}
}
This is what happens in the console. When I choose quit the error appears. I tried choosing Quit as first option and it does work but the problem appears in the 2nd loop.
1. Encrypt a file
2. Decrypt a file
3. Quit
What do you want to do(1/2/3): 1
1. Alpha
2. Binary
Choose data type(1/2): 1
Open the message file
laih wdi
Open the key file
tae
1. Encrypt a file
2. Decrypt a file
3. Quit
What do you want to do(1/2/3): 3
1. Alpha
2. Binary
Choose data type(1/2): Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Scanner.java:937)
at java.base/java.util.Scanner.next(Scanner.java:1594)
at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
at CipherServiceTest.WhatToDo(CipherServiceTest.java:27)
at CipherServiceTest.main(CipherServiceTest.java:9)
The root of the problem is main(null);. Don't do that, your program starts all over again, you have managed to do something like hidden recursion and the flow gets all jumbled up. Just use the while loop. Step through the code with a debugger to better understand what's actually happening and why it's happening.
Also as a rule of thumb, don't close scanner, or anything that reads input from System.in. This closes the underlying stream as well, and you don't want to close System.in. This causes the exception you see, though it's not the root problem.
Your second loop closes the scanner in your first loop,place use only one scanner
I am trying to program a method that handles user Input. The method needs to scan from the console an int, check if scanned int was in Range and then check the validity of the data before scanning another int in another method. I decided to program the method recursively, that it will call itself to repeat if the mentioned conditions are not met.
public static void readUserInputDay(Scanner scanner) {
System.out.print("Day (1-31): ");
try {
int tmp = scanner.nextInt();
day = new Integer(tmp);
if(isTheInputInRange(day.intValue(), DAY)) {
readUserInputMonth(scanner);
} else {
System.out.print("Number isn't in Range (1-31)\n");
readUserInputDay(scanner);
}
} catch (Exception e) {
System.out.print("Please enter a number!\n");
readUserInputDay(scanner);
}
}
The other filters work as expected, however if I enter on the console something that is not an int the Exception is triggered and catched (As expected) but when I expect the Method to recursively repeat itself, I instead get the following output on the console:
Day (1-31): Please enter a number!
Day (1-31): Please enter a number!
Day (1-31): Please enter a number!
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
at sun.nio.cs.UTF_8.access$200(UTF_8.java:57)
at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636)
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:669)
at MyClass.readUserInputDay(MyClass.java:27)
at MyClass.readUserInputDay(MyClass.java:43)
at MyClass.readUserInputDay(MyClass.java:43)
Do have any ideas how I need to fix the code, so when method call itself, it doesn't enter immediately in the catch block ?
Thanks in advance
you are calling the method inside of itself 3 times and according to conditions it cause to re-call it self and at the end overflow error.
to prevent from this problem at first try to change the structure of your code and use while loops for example to continue your code at a certain condition you want and get the result:
public static void readUserInputDay(Scanner scanner) {
try {
boolean isFinished = false;
// your condition for loop
while (!isFinished) {
System.out.print("Day (1-31): ");
int tmp = scanner.nextInt();
day = new Integer(tmp);
if (isTheInputInRange(day.intValue(), DAY)) {
readUserInputMonth(scanner);
isFinished = true;
} else {
System.out.print("Number isn't in Range (1-31)\n");
}
}
} catch (Exception e) {
System.out.print("Please enter a number!\n");
readUserInputDay(scanner);
}
}
It is odd that you say the StackOverflow error occurs on the first retry, especially within the first System.out.print call.
However, as Mustafa suggested, using a while loop rather than recursion is a much better choice in this case, as it will not cause new stack frames to be created every time somebody enters the wrong text (as I do not think that Java can do tail call optimisation on that method).
public static void readUserInputDay(Scanner scanner) {
while (true) {
System.out.print("Day (1-31): ");
try {
int tmp = scanner.nextInt();
day = new Integer(tmp);
if (isTheInputInRange(day.intValue(), DAY)) {
readUserInputMonth(scanner);
break; // exit the retry loop
} else {
System.out.print("Number isn't in Range (1-31)\n");
}
} catch (Exception e) {
System.out.print("Please enter a number!\n");
}
// By this point, the input is invalid, so loop again
}
}
I have some code that involves checking user input to see if it the input entered is a string or an int, and will execute different code depending on the result. I am using Integer.parseInt in order to determine if the user input is an integer or not, with the NumberFormatException being thrown if it is not.
However, in order to control the flow of the code, i am using a try/catch statement, with the catch block being used to contain code that will be run if the user's input is a string (i.e NumberFormatException) is thrown.
Qn
Is this an acceptable way of using the try/catch block? I've try googling this but all i could find were examples of the catch block being used to handle the Exception thrown instead of it being used as i am doing.
import java.io.*;
import java.util.*;
public class Datafile{
private static Scanner input = new Scanner(System.in);
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\Kence\\workspace\\Java 8 - Beyond the Basics - Working Files\\Practice Programs\\src\\Practice Data Edited",true));
String data = null;
boolean end = false;
boolean cont = true;
String dataEntered = null;
int menuChoice = printMenu();
while(!end){
switch(menuChoice){
case 1:
System.out.println("Please enter a line of data or press 0 to exit back to the main menu");
dataEntered = input.nextLine();
try {
if(Integer.parseInt(dataEntered) == 0){
break;
}
} catch (Exception e) {
data += dataEntered + "\n";
while(cont){
System.out.println("Data entered.Please enter the next line of data or press quit to exit back to the main menu.");
dataEntered = input.nextLine();
if(Integer.parseInt(dataEntered) == 0){
cont = false;
break;
}else{
data+= dataEntered;
System.out.println("Current data entered is " + dataEntered);
}
}
}
break;
case 2:
System.out.println("2 Entered");
break;
case 3:
System.out.println("3 Entered");
break;
case 4:
System.out.println("4 Entered");
break;
}//End of switch statement
menuChoice = printMenu();
}
input.close();
}//End of main
public static void printStars(){
for(int i = 0; i<66 ; i++){
System.out.print("*");
}
System.out.println();
}
public static int printMenu(){
printStars();
System.out.println("System Started");
printStars();
System.out.println("Enter 1 to input a new line of data");
System.out.println("Enter 2 to list all data");
System.out.println("Enter 3 to save existing data");
System.out.println("Enter 4 to load data");
printStars();
return Integer.parseInt(input.nextLine());
}
}
It isn't considered best practices to use a try/catch block for control flow, but it is "acceptable" if you don't care about best practices.
See Determine if a String is an Integer in Java for examples of other ways to check if a number is an integer. You could use one of those examples and then if it is an integer check if it's equal to zero.
Also, in your code it appears your second call to Integer.parseInt(dataEntered) could still throw an exception that would not be caught.
Exceptions should generally only be used in exceptional cases (see where the name comes from?). They are especially bad in tight loops because the execution overhead is high. Having invalid user input seems like a rather common occurrence, so I would look for another way. Take a look at this answer.
But this all depends on the language. In Python for example, try/catch is the de-facto way of coding (duck-typing).
I'm making a school assignment and this time around I thought about using a switch statement since it looked more efficient.
It's just something basic but if I enter a letter for example and after that number 1 for example it would return case 1 twice?
This is my code for the entire class so far:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test {
private int option;
public static void main(String[] args) {
Test t = new Test();
t.start();
t.optionMenu();
}
public void start() {
System.out.println("Make your choice:");
System.out.println("1: Play");
System.out.println("2: Options");
System.out.println("3: Exit");
}
public void optionMenu() {
try {
Scanner sc = new Scanner(System.in);
this.option = sc.nextInt();
System.out.println(this.option);
} catch (InputMismatchException e) {
System.out.println("Please enter a number");
optionMenu();
}
switch (this.option) {
case 1:
System.out.println("Game starting...");
break;
case 2:
System.out.println("Loading options");
break;
case 3:
System.out.println("Game exiting...");
System.exit(0);
break;
default:
System.out.println("Enter a valid number (1, 2 or 3");
break;
}
}
}
Any help would be much appreciated, thanks!
When you call sc.nextInt() without first asking if (sc.hasNextInt()), you are open to some strange behavior when end-users start typing unexpected input, such as letters. In this case the scanner would not advance its reading pointer, so your program will get stuck reading the same incorrect output.
To fix this issue, add a loop that "clears out" the invalid entry before attempting to read an int again, like this:
while (!sc.hasNextInt()) {
System.out.print("You need to enter an integer.");
sc.nextLine(); // Clear out the bad input
}
int val = sc.nextInt(); // At this point we know that sc.hasNextInt(), because that's the loop condition
Another point is that it is not a good idea to do with recursion what can be done with iteration: the recursive call to optionsMenu is going to accumulate as many levels of invocation as the number of times the end-user enters an incorrect value, so a very persistent user could theoretically force a stack overflow on your program by entering invalid data repeatedly.
Using the code fragment above would free you from the need to call optionsMenu recursively, and also from catching the input exception.
It's just something basic but if I enter a letter for example and after that number 1 for example it would return case 1 twice?
I'm not sure what you mean here. Firstly, your idea works, this code should be fine!
Second, if you enter anything besides just the number 1, 2, or 3, you will go to the "default:" block of code. Since you are prompting the user again if they fail, typing "a" or "a1" into the prompt just shows the menu again. The user needs to just type "1", "2", or "3" to successfully select a menu option.
I need help Using Exception handling with Wrong User Input. I am creating a text based game that welcomes the User and then goes to the main menu. It then tell the User the options, and then look for User input. For some Reason, whenever I input 1 or 2, It says: "Your input is invalid, please try again" And goes back to the choices. I don't know exactly where I am going wrong, hopefully someone can help me. Also, it won't catch the Mismatch Exception either. Hope you can Help! Thanks, Shandan
public static void main(String[] args) {
System.out.println("Welcome to Spec Ops!");
System.out.println("Please state your name:");
Scanner name = new Scanner(System.in);
String Name = name.next();
System.out.println("Hello "+Name);
mainMenu();
}
public static void mainMenu() {
System.out.println("1. Story Mode");
System.out.println("2. Infinant Combat");
Scanner input = new Scanner(System.in);
Object Selection = input.nextInt();
boolean validOption = true;
Integer x;
try {
x = (Integer)Selection;
} catch(ClassCastException cce){
System.out.println("Your input is invalid, please try again");
validOption = false;
} catch(InputMismatchException ime){
System.out.println("Your input is invalid, please try again");
validOption = false;
}
if(validOption) {
System.out.println("Hello!");
}
else {
mainMenu();
}
}
}
Scanner.nextInt returns ant int, so there is no need to go Object selection = scanner.nextInt(), and then cast to an int, you can merely have int selection = scanner.nextInt() and surround that in a try catch that chatches java.util.InputMismatchException, which is the exception thrown when the user types a letter and not an number
You can temporarily change your code and use the Pokemon exception handling and check the stack trace to see what kind of exception you should implement:
try {
//do something
} catch(Exception e) {
//Gotta catch 'em all!
e.printStackTrace();
}
Once you know the exact exception, put some breakpoints and refactor your code accordingly.
Also, you don't have to control the flow of your program by changing your boolean variable inside the catch blocks:
boolean isValidOption = false;
Integer x;
try {
x = (Integer)Selection;
isValidOption = true;
} catch...
When you read the name in you are using scanner.next(). This does not read in the end of line character, so when you call scanner.nextInt() it reads the new line and fails to parse as an int.
You should change the name reading to scanner.nextLine() and if you want to handle invalid int inputs from the user, the call to nextInt needs to be in your try block and catch the InputMismatchException instead of the ClassCastException.