JVM Exception handling flow of control - java

Sample code:
package com.company;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean continueInput = true;
do {
try {
System.out.println("Enter an integer");
int number = input.nextInt();
System.out.println("The number entered is " + number);
continueInput = false;
}
catch (InputMismatchException ex) {
System.out.println("Try again, enter integer only: ");
input.nextLine();
}
}
while (continueInput);
}
}
The above program is to test the InputMismatch exception class. I am not sure at what point the flow of control is passed to the catch block when a letter is entered. Specifically, which scenario happens?
a) The JVM outputs "Enter an integer" and the user types in the letter B. Does the letter B get assigned to the variable number of type int, and then an exception occurs because of this incompatibility OR
b) The JVM outputs "Enter an integer" and the user types in the letter B. Does the input get checked first to determine if it is an Integer and if not throw an exception to transfer control to the catch block?
or
C) None of the above?
I think it is a bit of B and C.

nextInt() is defined as returning an int. So it has to check the input and convert it to an int. If it can't make an int out of it, it can't just return any old thing (like a letter or a String), because it can only return int.
In that case, it doesn't return at all. It throws an exception. The statement that called nextInt() is abandoned; nothing else happens in that statement. In Java terminology, it completes abruptly. If there were other methods that the statement was going to call, they don't get called. If there was an assignment that the statement was going to perform, it doesn't happen. That's how exceptions work.
And any statement after that statement doesn't get executed, either--they just get skipped.
In this case, the statement
int number = input.nextInt();
gets completed abruptly. Since it's in a try block, though, the program then sees if there's a catch block for the exception. In this case, there is. So after the above statement gets completed abruptly, the program jumps over everything else to the first statement in the catch block.
If there were no try block, however, the whole method would be completed abruptly. Then the statement that called that method would also complete abruptly, which could cause the method that it's in to complete abruptly, and so on until it's either caught or causes your program to crash with a stack trace.
Please try the Oracle tutorials on exceptions (https://docs.oracle.com/javase/tutorial/essential/exceptions/handling.html) for more information on how exceptions work.

Related

Java prints repeatedly if try catch is used

I am making a basic application where it trains your math skills. I have this code:
while (true)
{
try
{
int userAnswer;
System.out.println("Type quit to exit to the menu!");
int randInt = r.nextInt(num2);
System.out.println(num1 + " + " + randInt + " =");
userAnswer = in.nextInt();
if(userAnswer == num1 + randInt) System.out.println("Correct!");
else System.out.println("Wrong!");
break;
}
catch(Exception e)
{
}
}
When someone prints out a d or something in the answer, the try catch goes. But, then it goes to the while loop and repeatedly spams Type quit to exit to the menu and then something like 1 + 2 = infinitely... I think I know what's wrong, userAnswer has been assigned already as something that throws an exception that goes to the catch and it just keeps printing those and goes to the catch and goes back because userAnswer is already assigned. I think this is what is happening, I could be wrong. Please help!
EDIT: I forgot to make this clear, but I want the question to be re-printed again, exiting out of the loop goes to a menu where you can't get the question back, I want it to redo what's in the try catch...
You should never catch an Exception without handling it.
catch(Exception e)
{
System.out.println("An error has occured");
break;
}
This should stop your program from looping infinitely if an Exception occurs.
If user input comes as letter it will get an exception because you are trying to read(parse) as integer. So your catch clause is in the loop you have to write break in there to go out from loop.
Still i will suggest you to getline as string and than compare with your cli commands (quit in your case) than you can try to parse it as an integer and handle loop logic.
You're not breaking the while loop if there is a mismatch
while(true)
{
try
{
}
catch(InputMisMatchException e)//I suggest you to use the exact exception to avoid others being ignored
{
System.out.println("Thank you!");
break;//breaks the while loop
}
}
Yoy're not breaking the loop in case of Exception occurs.
Add break; statement in the catch block to run your program without going to infinite loop, in case exception occurs.
Since the given answers don't match your requirement I'll solve that "riddle" for you.
I guess what you didn't knew is that the scanner won't read the next token if it doesn't match the expectation. So, if you call in.nextInt() and the next token is not a number, then the scanner will throw an InputMismatchException and keeps the reader position where it is. So if you try it again (due to the loop), then it will throw this exception again. To avoid this you have to consume the erroneous token:
catch (Exception e) {
// exception handling
in.next();
}
This will consume the bad token, so in.nextInt() can accept a new token. Also there is no need to add break here.
Mind that in.next() reads only one token, which is delimited by a whitespace. So if the user enters a b c, then your code will throw three exception and therefore generate three different question befor the user can enter a number. You can avoid that by using in.nextLine() instead. But this can lead into another problem: Scanner issue when using nextLine after nextXXX, so pay attention to that :).

Floating-Point Variables and Exception Handling

My program is supposed to accept a floating-point variable and then exit. However I am practicing some exception handling stuff and found a problem. Whenever you enter a letter into this program the program of course throws an InputMismatchException but it gets stuck inside an infinite loop. I assume my problem is based off of my misunderstanding of try-catch statements and exception handling.
public static void main(String [] args){
Scanner reader = new Scanner(System.in);
boolean done = false;
do{
try{
System.out.print("Enter a number: ");
float number = reader.nextFloat();
done = true;
}
catch (Exception e){
System.out.println("uh oh");
}
}while(!done);
}
This problem does not occur if I use a different variable type so I'm not sure if it's a logical error or just something funky with floating-point variables.
Float#nextFloat() does not consume the token in the Scanner if it throws an InputMismatchException. So when you get the exception and loop (because done is still false), you try to call nextFloat() again. Since the token is still not a value that can parsed into a float, the Scanner again throws the exception. And again, and again, ad nauseam.
You should use hasNextFloat() to check for the existence of a token that can be parsed to a float value. Or consume the incorrect value with Scanner#next(), as suggested by Quirliom.

An infinite loop owing to recursion (introductory)

I was trying to write a method that enables one to input integers via Scanner without the program crashing due to exceptions. Here's what I initially had:(here, sc is a Scanner object)
public static int inputInt(String message) {
int returnval = 0;
System.out.println(message);
try {
returnval = sc.nextInt();
} catch (Exception ex) {
System.out.println("You must enter an integer.");
inputInt(message);
}
return returnval;
}
When I tested the program with an invalid input, an infinite loop was initiated, with the message and "You must enter an integer" being printed many times before being halted by Eclipse.
I fixed this using the following code:
public static int inputInt(String message) {
int returnval = 0;
System.out.println(message);
String valstring = sc.nextLine();
try {
returnval = Integer.parseInt(valstring);
} catch (Exception ex) {
System.out.println("You must enter an integer.");
inputInt(message);
}
return returnval;
}
Why does the first method fail, but not the second? Might there be a cleaner way to accomplish this?
Yes, there is a cleaner way: use hasNextInt:
public static int inputInt(String message) {
System.out.println(message);
while (!sc.hasNextInt()) {
sc.nextLine(); // clear the bad input first
System.out.println("You must enter an integer.");
System.out.println(message); // why use recursion? just use a while loop
}
return sc.nextInt();
}
The changes I made:
Uses hasNextInt, so you don't have to use exceptions
Added sc.nextLine(); (the root of your problem)
Instead of recursion, just does a while loop (why recurse when you can simple loop?)
Eliminated temporary variable
Made it more readable (IMO)
Problem
Scanner.nextInt() has the capacity of throwing 3 exceptions:
1- InputMismatchException: Thrown when the next item isn't an int.
2- NoSuchElementException: When there isn't a next anything.
3- IllegalStateException: If the Scanner has been closed.
So when you enter an illegal value, such as "abc" for example, the top piece of code does this:
Takes "abc" and tries to convert it to an int. (nextInt()). Because "abc" isn't a number, it cannot convert, and throws an InputMismatchException. However, beacuse the method didn't complete successfully, "abc" is left as the next item to be read. Because the exception was thrown, the code inside your catch block is run. It prints out "You must enter an integer." Then it calls itself again, passing itself message. It then initialises returnval and prints out the same message from the first run, because you passed it to yourself again. Then you enter the try block, where, because "abc" wasn't read successfully and left there, the scanner reads "abc" and tries to convert it to an int again. Of course, this won't work, and the cycle starts again.
Solution
Now you know what your problem is, you can figure out a solution. The most elegant in my mind would be to use the Scanner method, hasNextInt(). This will return a boolean letting you know if the next item to be read can be converted to an int. For example, if the next item is "abc", the method will return false. For the next item "1", the method will return true. So, if you modify your code like so, it should work:
public static int inputInt(String message) {
int returnval = 0;
System.out.println(message);
while(!sc.hasNextInt()) {
sc.nextLine();
System.out.println("You must enter an integer.");
}
returnval = sc.nextInt();
return returnval;
}
What this code does:
1- Initializes returnval and prints out message.
2- Enters the while loop as long as the scanner doesn't have an int to read. Effectively "waiting" for the next int to be input.
3- Once it has an int to read, it reads the int and saves the value in returnval.
4- It returns returnval to the caller.
(Slow and steady wins the race, lol. I always seem to be the slow one to answer. Maybe because I write small novels as answers.... ;))

how to catch a NoSuchElementException?

My class assignment is to write a program that has the user input a set of numerical values. If the user enters a value that is not a number, the program is supposed to give the user 2 second chances to enter a number correctly, and after those two chances, quit asking for input and print the sum of all values entered correctly so far.
As is, my code doesn't work quite right. When the first non-number is entered, the program executes the code in the catch block once, prints the "gimme input" line at the beginning of the try block but then immediately executes the code in the catch block again without waiting for the user to enter another number.
While perusing my textbook for clues, I noticed this line: "A NoSuchElementException is not caught by any of the catch clauses. The exception remains thrown until it is caught by another try block or the main method terminates."
Which is great, because now at least I know there's a good reason this is happening, but my textbook doesn't contain any further information on this quirk, and I haven't been able to find any understandable answers via StackOverflow or Google. So my question is two part:
a) How should I get around this for the purposes of this assignment?
b) What exactly does it mean that the exception is not caught by a catch clause? Isn't that what catch clauses exist for? I do want a solution to my assignment, but I also want to understand why this is the way it is, if possible.
Thanks for any help!
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.ArrayList;
import java.util.Scanner;
public class NotANumber {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("This program computes the sum of any number of real numbers. When you are done entering values, enter something other than a real number twice in a row.\n");
ArrayList<Double> numbers = new ArrayList<Double>();
int count = 0;
while (count < 2) {
try {
System.out.println("Please enter a floating point number: ");
double newNumber = in.nextDouble();
numbers.add(newNumber);
count = 0;
}
catch (NoSuchElementException exception) {
System.out.println("The value entered was not correctly specified. All values must be integers or floating point values.");
count++;
}
}
if (!numbers.isEmpty()) {
double sum = 0;
for (Double each : numbers) {
sum = sum + each;
}
System.out.println("The sum is " + sum);
}
else {
System.out.println("There is no sum as no correctly specified values were entered.");
}
}
}
For now, forget about catching the exception (it isn't what you want to do!). What you want to do is add calls like: s.hasDouble() before calling s.nextDouble().
The reason you don't want to catch that exception is because it is a RuntimeException which is meant to be used to indicate a programmer mistake, one that you should fix.
The simple advice is don't catch exceptions that the compiler doesn't tell you to catch, instead if one of them is thrown figure out the change you need to make to your code so that exception doesn't happen.
For exceptions the compiler tells you that you must deal with them you do something like:
try
{
foo();
}
catch(final IOException ex)
{
// do something smarter here!
ex.printStackTrace();
}
In that code, foo() is declared something like:
public void foo()
throws IOException
{
// ... code ...
}
IOException is a checked exception (RuntimeException, also called unchecked exceptions, should not be caught, checked exceptions must be caught... well you can do other things beyond catch, but for now don't worry about those).
So, long answer short, make the exception not happen by calling s.hasXXX() before calling s.nextXXX().
You are mistaken: Scanner.nextDouble throws a NoSuchElementException if the input is exhausted, which is unlikely to happen with standard input (it will block instead). An incorrect value will produce an InputMismatchException.
My guess, however, is that nextDouble does not remove the offending value from the stream on failure. You'll need to "clear" the input in your catch before resuming the read.
#TofuBear states:
The simple advice is don't catch exceptions that the compiler doesn't tell you to catch, instead if one of them is thrown figure out the change you need to make to your code so that exception doesn't happen.
I think that's an over-simplification.
It is true that exceptions that are declared as checked exceptions HAVE to be either caught or declared as thrown in the method signature.
It is also true that you don't have to catch unchecked exceptions, and indeed that you should think carefully about whether it wise to catch an unchecked. (For instance, you should think whether the exception is being thrown at the point you expect and for the reasons that you expect.)
However, in some circumstances it is clearly necessary to catch them. For instance:
try {
System.out.println("Enter a lucky number!");
String input = // get string from user
int number = Integer.parseInt(input);
...
} catch (NumberFormatException ex) {
System.err.println("Bad luck! You entered an invalid number");
}
If you didn't catch NumberFormatException ... which is an unchecked exception ... then you wouldn't be in position to print out a friendly message, and ask the user to try again.
In short, unchecked exceptions don't always mean programmer error.
A few of the standard ones could indicate bad input from a user or client (e.g. NumberFormatException, IllegalArgumentException, ArithmeticException, etc), or they could indicate something that a specific application can recover from, or at least attempt to diagnose.
I've come across third party libraries where the designer has an aversion to checked exceptions and has declared all library exceptions as unchecked. (Bad design IMO, but it happens ...)
So a blanket statement that you shouldn't catch unchecked exceptions is clearly wrong advice.
However the second part of #TofuBear's advice is valid. It is (generally) a better idea to do a test to prevent an anticipated exception from happening than to do the action and catch the exception. (The code is typically simpler, and typically more efficient ... though there are counter examples.)
In this case, if you call and test hasNextDouble() before nextDouble() you can avoid the error case you are trying to handle with the try / catch.
surround your statements around try..catch is a good idea when you have no clue that what will happen in real scenario. but i have alternative solution, most of the time we know this exception raise so you can avoid it using implementing iterator as follows..
for (ListIterator<Double> iter = numbers.listIterator(); iter.hasNext(); ) {
if(iter.hasNext()) { // this return false in case of NoSuchElementException
// do your stuff here
}
}
You must change import.
Instead of
import java.util.NoSuchElementException;
use
import org.openqa.selenium.NoSuchElementException;

JAVA - Having difficulties with Try / Catch

I'm writing a straight forward Airport Terminal style program for class. I'm going beyond the scope of the assignment and "attempting" to use Try/Catch blocks...
However Java is being that guy right now.
The problem is that when someone enters a non-letter into the following code it doesn't catch then return to the try block it caught...
Why?
Edit - Also the containsOnlyLetters method works, unless someone thinks that could be the error?
System.out.println("\nGood News! That seat is available");
try
{//try
System.out.print("Enter your first name: ");
temp = input.nextLine();
if (containsOnlyLetters(temp))
firstName = temp;
else
throw new Exception("First name must contain"
+ " only letters");
System.out.print("Enter your last name: ");
temp = input.nextLine();
if (containsOnlyLetters(temp))
lastName = temp;
else
throw new Exception("Last name must contain"
+ " only letters");
}//end try
catch(Exception e)
{//catch
System.out.println(e.getMessage());
System.out.println("\nPlease try again... ");
}//end catch
passengers[clients] = new clientInfo
(firstName, lastName, clients, request, i);
bookSeat(i);
done = true;
You seem to misunderstand the purpose and mechanism of try/catch.
It's not intended for general flow control, and more specifically, the meaning is not that the try block is repeated until it finishes without an exception. Instead, the block is run only once, the point is that the catch block will only execute if a matching exception is thrown.
You should use a while loop and if clauses for your code, not try/catch.
If a Throwable or Error is generated it won't be caught by your handler. You could try catching Throwable instead.
What do you mean when you say
when someone enters a non-letter into the following code it doesn't catch then return to the try block it caught...
It is not clear the outcome you expect, are u thinking that once the exception is caught, control will go back into the try block? That is not how it is intended to work.
When an exception is thrown, the control goes to the appropriate catch/finally blocks and then moves ahead, remaining lines in the try block are not executed

Categories