Under What Conditions Must a Throws Clause Be Added to a Method Signature
At present that nosotros're writing specifications and thinking about how clients will employ our methods, let'southward discuss how to handle infrequent cases in a manner that is safe from bugs and easy to understand.
A method's signature — its name, parameter types, render blazon — is a core part of its specification, and the signature may besides include exceptions that the method may trigger.
Exceptions for signaling bugs
You've probably already seen some exceptions in your Java programming so far, such as ArrayIndexOutOfBoundsException
(thrown when an assortment index foo[i]
is exterior the valid range for the assortment foo
) or NullPointerException
(thrown when trying to call a method on a null
object reference). These exceptions mostly indicate bugs in your code, and the information displayed by Coffee when the exception is thrown tin help you lot find and fix the bug.
ArrayIndexOutOfBounds-
and NullPointerException
are probably the most common exceptions of this sort. Other examples include:
-
ArithmeticException
, thrown for arithmetic errors like integer division by zero. -
NumberFormatException
, thrown past methods likeInteger.parseInt
if you pass in a string that cannot be parsed into an integer.
Exceptions for special results
Exceptions are not only for signaling bugs. They tin be used to improve the construction of code that involves procedures with special results.
An unfortunately common fashion to handle special results is to render special values. Lookup operations in the Coffee library are oftentimes designed like this: you get an alphabetize of -i when expecting a positive integer, or a cipher
reference when expecting an object. This arroyo is OK if used sparingly, only it has two problems. First, information technology's deadening to check the return value. Second, it'due south piece of cake to forget to do it. (We'll see that past using exceptions you lot can get help from the compiler in this.)
Also, it's not always easy to find a 'special value'. Suppose we accept a BirthdayBook
class with a lookup method. Here's i possible method signature:
form BirthdayBook { LocalDate lookup (String name) { ... } }
(LocalDate
is part of the Java API.)
What should the method practise if the altogether book doesn't accept an entry for the person whose proper name is given? Well, we could return some special date that is not going to exist used as a real engagement. Bad programmers take been doing this for decades; they would return 9/9/99, for case, since it was obvious that no program written in 1960 would however exist running at the finish of the century. (They were wrong, past the way.)
Here'south a amend approach. The method throws an exception:
LocalDate lookup (String name) throws NotFoundException { ... if ( ...not found... ) throw new NotFoundException(); ...
and the caller handles the exception with a catch
clause. For example:
BirthdayBook birthdays = ... endeavour { LocalDate birthdate = birthdays.lookup("Alyssa"); // we know Alyssa's birthday } take hold of (NotFoundException nfe) { // her birthday was not in the birthday book }
Now there'south no need for whatsoever special value, nor the checking associated with it.
Reading exercises
1st birthday
Assume nosotros're using BirthdayBook
with the lookup
method that throws NotFoundException
.
Presume we have initialized the birthdays
variable to point to a BirthdayBook
, and assume that Elliot is not in that birthday book.
What volition happen with the post-obit lawmaking:
try { LocalDate birthdate = birthdays.lookup("Elliot"); }
(missing explanation)
2d altogether
try { LocalDate birthdate = birthdays.lookup("Elliot"); } grab (NotFoundException nfe) { birthdate = LocalDate.now(); }
(missing explanation)
3rd birthday
try { LocalDate birthdate = birthdays.lookup("Elliot"); } grab (NotFoundException nfe) { throw new DateTimeException("Missing reference altogether", nfe); }
(DateTimeException
is provided by the Java API.)
(missing explanation)
Checked and unchecked exceptions
We've seen two dissimilar purposes for exceptions: special results and bug detection. Equally a general rule, you'll want to employ checked exceptions to signal special results and unchecked exceptions to signal bugs. In a later section, nosotros'll refine this a bit.
Some terminology: checked exceptions are called that because they are checked by the compiler:
- If a method might throw a checked exception, the possibility must be alleged in its signature.
NotFoundException
would be a checked exception, and that's why the signature endsthrows NotFoundException
. - If a method calls another method that may throw a checked exception, information technology must either handle it, or declare the exception itself, since if it isn't defenseless locally it will exist propagated up to callers.
And then if you call BirthdayBook
's lookup
method and forget to handle the NotEstablishException
, the compiler will reject your code. This is very useful, considering information technology ensures that exceptions that are expected to occur will be handled.
Unchecked exceptions, in contrast, are used to signal bugs. These exceptions are not expected to be handled by the code except mayhap at the top level. Nosotros wouldn't want every method up the call chain to have to declare that it (might) throw all the kinds of bug-related exceptions that tin happen at lower call levels: index out of bounds, zip pointers, illegal arguments, assertion failures, etc.
Equally a consequence, for an unchecked exception the compiler will non check for try
-catch
or a throws
declaration. Coffee all the same allows you to write a throws
clause for an unchecked exception as office of a method signature, simply this has no effect, and is thus a bit funny, and we don't recommend doing information technology.
All exceptions may have a bulletin associated with them. If not provided in the constructor, the reference to the bulletin string is null
.
Throwable hierarchy
To empathize how Java decides whether an exception is checked or unchecked, let'southward wait at the course hierarchy for Coffee exceptions.
Throwable
is the form of objects that can be thrown or defenseless. Throwable
's implementation records a stack trace at the point where the exception was thrown, along with an optional string describing the exception. Whatsoever object used in a throw
or catch
argument, or declared in the throws
clause of a method, must be a subclass of Throwable
.
Error
is a subclass of Throwable
that is reserved for errors produced by the Coffee runtime system, such as StackOverflowError
and OutOfMemoryError
. For some reason AssertionError
besides extends Mistake
, even though it indicates a bug in user code, not in the runtime. Errors should be considered unrecoverable, and are mostly not defenseless.
Here's how Java distinguishes between checked and unchecked exceptions:
-
RuntimeException
,Error
, and their subclasses are unchecked exceptions. The compiler doesn't require them to be declared in thethrows
clause of a method that throws them, and doesn't require them to exist defenseless or alleged by a caller of such a method. - All other throwables —
Throwable
,Exception
, and all of their subclasses except for those of theRuntimeException
andError
lineage — are checked exceptions. The compiler requires these exceptions to be caught or declared when it's possible for them to be thrown.
When yous define your own exceptions, you should either subclass RuntimeException
(to get in an unchecked exception) or Exception
(to make it checked). Programmers mostly don't bracket Error
or Throwable
, considering these are reserved by Java itself.
Reading exercises
Get to the indicate
Suppose we're edifice a robot and we want to specify the function
public static Listing<Bespeak> findPath (Point initial, Point goal)
which is responsible for path-finding: determining a sequence of Point
southward that the robot should motility through to navigate from initial
to goal
, past any obstacles that might be in the way.
In the postcondition, we say that findPath
will search for paths only up to a bounded length (set elsewhere), and that information technology will throw an exception if it fails to find ane.
(missing answer)
(missing answer)
(missing answer)
(missing answer)
(missing caption)
Don't point that matter at me
(missing answer)
(missing answer)
(missing answer)
(missing answer)
(missing explanation)
Exception pattern considerations
The rule nosotros have given — use checked exceptions for special results (i.east., anticipated situations), and unchecked exceptions to point bugs (unexpected failures) — makes sense, simply information technology isn't the stop of the story. The snag is that exceptions in Java aren't as lightweight as they might be.
Aside from the performance punishment, exceptions in Java incur some other (more than serious) cost: they're a hurting to apply, in both method design and method apply. If you lot blueprint a method to have its ain (new) exception, you take to create a new course for the exception. If you phone call a method that tin can throw a checked exception, yous have to wrap it in a attempt
-catch
argument (fifty-fifty if you know the exception will never exist thrown). This latter stipulation creates a dilemma. Suppose, for instance, you lot're designing a queue abstraction. Should popping the queue throw a checked exception when the queue is empty? Suppose you want to support a style of programming in the client in which the queue is popped (in a loop say) until the exception is thrown. And so you lot choose a checked exception. At present some client wants to use the method in a context in which, immediately prior to popping, the customer tests whether the queue is empty and merely pops if information technology isn't. Maddeningly, that client volition yet need to wrap the call in a try
-take hold of
statement.
This suggests a more refined rule:
- You should use an unchecked exception only to signal an unexpected failure (i.e. a bug), or if y'all look that clients will usually write code that ensures the exception will not happen, because there is a convenient and inexpensive fashion to avoid the exception;
- Otherwise you should use a checked exception.
Here are some examples of applying this rule to hypothetical methods:
-
Queue.pop()
throws an uncheckedEmptyQueueException
when the queue is empty, considering information technology'south reasonable to expect the caller to avoid this with a telephone call likeQueue.size()
orQueue.isEmpty()
. -
Url.getWebPage()
throws a checkedIOException
when it can't call back the web page, considering it's not like shooting fish in a barrel for the caller to forbid this. -
int integerSquareRoot(int x)
throws a checkedNotPerfectSquareException
whenx
has no integral square root, considering testing whetherten
is a perfect square is simply as hard equally finding the actual square root, and then information technology's non reasonable to await the caller to prevent it.
The cost of using exceptions in Java is 1 reason that many Java API's apply the nix reference as a special value. It's not a terrible thing to do, then long equally it's done judiciously, and carefully specified.
Corruption of exceptions
Here'southward an case from Constructive Java past Joshua Bloch (Item 57 in the 2d edition).
attempt { int i = 0; while (true) a[i++].f(); } catch (ArrayIndexOutOfBoundsException eastward) { }
What does this lawmaking do? Information technology is not at all obvious from inspection, and that's reason enough non to use it. … The space loop terminates past throwing, catching, and ignoring an
ArrayIndexOutOfBoundsException
when it attempts to access the offset array element outside the premises of the array.
It is supposed to be equivalent to:
for (int i = 0; i < a.length; i++) { a[i].f(); }
Or (using advisable type T
) to:
for (T x : a) { x.f(); }
The exception-based idiom, Bloch writes:
… is a misguided effort to improve performance based on the faulty reasoning that, since the VM checks the premises of assortment accesses, the normal loop termination test (
i < a.length
) is redundant and should be avoided.
Notwithstanding, because exceptions in Java are designed for use only under infrequent circumstances, few, if any, JVM implementations attempt to optimize their operation. On a typical machine, the exception-based idiom runs seventy times slower than the standard one when looping from 0 to 99.
Must worse than that, the exception-based idiom is not fifty-fifty guaranteed to work! Suppose the ciphering of f()
in the body of the loop contains a bug that results in an out-of-bounds admission to some unrelated array. What happens?
If a reasonable loop idiom were used, the bug would generate an uncaught exception, resulting in firsthand thread termination with a full stack trace. If the misguided exception-based loop were used, the issues-related exception would be defenseless and misinterpreted equally a normal loop termination.
Reading exercises
Throw all the things!
Examine this code for doing some things:
static void doEverything () { doThingsInOrder(); } static void doThingsInOrder () { try { for (Thing t : ALL_THE_THINGS) { doTheThing(t); } } catch (ThingException te) { return; } } static void doTheThing (Thing t) throws ThingException { // ... // ... maybe go off the cease of an array // ... }
ThingException
is an unchecked exception.
(missing respond)
(missing respond)
(missing answer)
(missing answer)
(missing reply)
(missing explanation)
A terrible thing
(missing answer)
(missing answer)
(missing answer)
(missing explanation)
Next: Summary
Source: https://web.mit.edu/6.005/www/fa15/classes/06-specifications/exceptions/
0 Response to "Under What Conditions Must a Throws Clause Be Added to a Method Signature"
Post a Comment