问题
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.");
}
}
}
回答1:
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()
.
回答2:
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.
回答3:
@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.
回答4:
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
}
}
来源:https://stackoverflow.com/questions/5672134/how-to-catch-a-nosuchelementexception