Checked and unchecked exceptions (Section 8.1)
String parsing exceptions
Multiple catch blocks
Variables in try clauses
Exercise
Textbook: Section 8.1
Sometimes, the Java compiler will insist that you catch a particular type of exception. These are called unchecked exceptions because Java will not insist that they be checked. The exceptions we've mentioned so far have all been unchecked.
One example of a method that throws a checked exception is Thread.sleep(), which will halt for a number of milliseconds specified as a parameter.
This method can throw an InterruptedException, indicating that the method wasn't able to sleep as long as requested because of some other signal it received. Java will refuse to compile any code that calls Thread.sleep() but doesn't specifically handle this exception.Thread.sleep(20); // won't compile: exception not caught
So what you must do is place the code that uses Thread.sleep() within a try clause, followed by a catch clause to handle an InterruptedException.
Notice that here, we've told Java to do nothing when the exception occurs - essentially, we just want to ignore the exception. For this particular exception, this is frequently the best thing you can do.try { Thread.sleep(20); } catch(InterruptedException e) { }
(In fact, we used Clock.sleep() in Labs 2 and 4, defined in the csbsju.cs160 package. We did this instead of using the Thread class in the java.lang package because doing that instead would force us to worry about this checked exception, and we hadn't studied exceptions yet.)
The Integer.parseInt() and Double.parseDouble() class methods both take a String parameter and converts it into a number. But what if the string doesn't look like a number? Then it throws an exception (a NumberFormatException, in this case).
Integer.parseInt() will raise a NumberFormatException if the line contains any characters that don't belong in a number. This provides a more robust technique for checking the user's input. So the user might experience the following.try { IO.print("Type a number: "); String str = IO.readLine(); int i = Integer.parseInt(str); IO.println(2 * i); } catch(NumberFormatException e) { IO.println("That's not a number."); }
On the other hand, if there wasn't a problem with what the user types, it would simply proceed normally.Type a number: 3 2 That's not a number.
Type a number: 45 90
Occassionally, you may run into a situation where you want multiple catch blocks for the same try block. You can get around this by stringing the catch blocks together, as the following illustrates.
try { IO.println("Type two numbers to divide."); int m = Integer.parseInt(IO.readLine()); int n = Integer.parseInt(IO.readLine()); IO.println(m / n); } catch(NumberFormatException e) { IO.println("That's not a number."); } catch(ArithmeticException e) { IO.println("I can't divide by zero."); }
Quite frequently you'll want to declare a variable in a try block that you want to use after the try block. Like all other statement blocks, variables declared inside the block can't be used outside the block. You might want to write the former as follows.
This won't compile, since in the expression m / n, neither m nor n are defined as variables. (We did define them in the first try block, but in the second try block we were beyond the closing brace enclosing their definition, so that definition no longer applies.)IO.println("Type two numbers to divide."); try { int m = Integer.parseInt(IO.readLine()); int n = Integer.parseInt(IO.readLine()); } catch(NumberFormatException e) { IO.println("That's not a number."); } try { IO.println(m / n); // ERROR: won't compile } catch(ArithmeticException e) { IO.println("I can't divide by zero."); }
So to make this strategy work, you'd need to declare the variables outside the block. We'll also want to give these variables an initial value, in case an exception raised inside the first block could prevent one from getting a value otherwise.
Frankly, I prefer my earlier solution with multiple catch blocks more.IO.println("Type two numbers to divide."); int m = 0; int n = 1; try { m = Integer.parseInt(IO.readLine()); n = Integer.parseInt(IO.readLine()); } catch(NumberFormatException e) { IO.println("That's not a number."); } try { IO.println(m / n); // ERROR: won't compile } catch(ArithmeticException e) { IO.println("I can't divide by zero."); }
Generally, exceptions are an important but irritating part of Java programming. You can't really ignore them, but unfortunately neither can you assume the outside world will always give you proper values with which to do your work.