How to fix the Stackoverflow in the following method? - java

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
}
}

Related

Try Catch InputMismatchException not actually catching my Error

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);
}

How to keep looping with try and catch to get correct input?

I'm trying to make a function that checks for an integer and will keep looping until the user correctly enters an integer of 17 or higher. However, if I put in wrong input, like 'K', or '&', it will get stuck in an infinite loop.
public static int getAge(Scanner scanner) {
int age;
boolean repeat = true;
while (repeat) {
try
{
System.out.println("Enter the soldier's age: ");
age = scanner.nextInt();
repeat = false;
}
catch(InputMismatchException exception)
{
System.out.println("ERROR: You must enter an age of 17 or higher");
repeat = true;
}
}
return age;
}
If next available input token isn't an integer, nextInt() leaves that input unconsumed, buffered inside the Scanner. The idea is that you might want to try to read it with some other Scanner method, such as nextDouble(). Unfortunately, this also means that unless you do something to get rid of the buffered-up garbage, your next call to nextInt() will will just try (and fail) to read the same junk over again.
So, to flush out the junk, you need to call either next() or nextLine() before trying to call nextInt() again. This ensures that the next time you call nextInt(), it will have new data to work on instead of the same old garbage:
try {
//...
}
catch(InputMismatchException exception)
{
System.out.println("ERROR: You must enter an age of 17 or higher");
scanner.next(); // or scanner.nextLine()
repeat = true;
}
I would not pass a scanner to your method I would try re structuring it, and assigning the method to a variable in your main like this:
I am also using recursion in my catch to recall the method when the exception is caught, id also recommend using maybe a general exception , making it catch(Exception exception)
main method call of method
---------------------------
int something= getAge();
----------------------------------------------------------
method structure like this,
---------------------------------------------
public static int getAge() {
int age;
age = scanner.nextInt();
boolean repeat = true;
while (repeat) {
try
{
System.out.println("Enter the soldier's age: ");
if(age<=17){
repeat = false;
}
if(age>17){
getAge();
}
}
catch(InputMismatchException exception)
{
System.out.println("ERROR: You must enter an age of 17 or higher");
getAge();
}
}
return age;
}
<!-- end snippet -->

Java try-catch infinite loop when input a character

I want to make a try-catch exception that only accept 1-5 or 9 input. So I wrote the following code.
try {
step1 = scanner.nextInt();
} catch (Exception ex) {
System.out.println("Error! Input accept integers only. Input 1-5 or 9");
System.out.println("");
continue;
}
The result is that if I input an invalid number, it gave me an error (That's true). But when I input a character, it gave me an infinite loop. How can I solve the problem?
Since i don´t know how your loop looks i´ll just go with an endless loop in my answer. In the normal case, the nextInt method wont catch the carriage return, and if you input something that is not a number you need to call nextLine to catch this. If you don´t do this you might run into an infinity loop if you are using any kind of loop that just asks for nextInt. This could solve the problem:
while(true) {
int step1;
try {
step1 = s.nextInt();
} catch (InputMismatchException e) {
System.out.println("Error! Input accept integers only. Input 1-5 or 9");
System.out.println("");
} finally { // Use a finally block to catch the carriage return, no matter if the int that got input was valid or not.
s.nextLine();
}
}
Maybe you must parse input before decision making.
Sorry for my bad English, I'm not a native speaker also.
try this, which make all the tests
int step1;
while (true)
{
Scanner scanner = new Scanner(System.in);
try {
step1 = scanner.nextInt();
if (((step1>=1) && (step1<=5)) || (step1==9))
// BINGO
break;
}
catch (Exception ex)
{
}
System.out.println("Error! Input accept integers only. Input 1-5 or 9");
System.out.println("");
// it loops ther
}
System.out.println("You are done ! "+step1);

(Java) Unable to catch an Exception

I'm a beginner with Java and was attempting to catch the exception 'InputMismatchException'. Below is my code, I hope it is easy to read, apologies in advance if it's not formatted well. It builds fine and executes, but if I input a character for example the 'catch' doesn't function and the error comes up;
"Exception in thread "main" java.util.InputMismatchException"
I believe everything else in the code works fine including the 'try', and I don't have anything going in the catch other than a System.out.print command.
import java.util.*; // imports
public class w4q1
{
public static void main(String[] args)
{
Scanner user_input = new Scanner( System.in ); // declaring Scanner util
System.out.print("Please enter an integer: \n"); // Asks for input
int d = user_input.nextInt();
while (d > 0 || d < 0) // start of while loop, in the event of anything other than zero entered
{
try {
if (d < 0) // if statements
{
System.out.print("The integer " + d + " is negative\n");
break;
}
else if (d > 0)
{
System.out.print("The integer " + d + " is positive\n");
break;
}
else
{
System.out.print("You have not entered an integer\n");
break;
}
}
catch (InputMismatchException e) // Error message for letters/characters and decimals
{
System.out.print("You have entered an incorrect value, please restart the program\n");
}
}
if (d == 0)
{
System.out.print("A zero has been entered\n");
}
}
}
If you are still receiving an InputMismatchException even though you have a try-catch block, then the exception must be coming from somewhere outside of your try-catch block.
Look at what else outside the try-catch block can throw an InputMismatchException and put a try-catch block around that statement, or expand your existing try-catch block to include that statement.
If indeed the exception is not getting caught, then the resulting stack trace should show you the actual line of code which threw the exception. Looking at the code, I'm going to guess that this is where the exception occurs:
user_input.nextInt();
I would recommend you look at the stack trace and see if you can confirm this.
Put a try-catch block around this code
int d = user_input.nextInt();
and by so doing ,you also need to change the current code a little bit to make it OK. Good Luck !

Exception Handling with wrong User Input Java

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.

Categories