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 ArrayIndex­OutOfBounds­Exception (thrown when an assortment index foo[i] is exterior the valid range for the assortment foo) or Null­Pointer­Exception (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.

ArrayIndex­OutOfBounds- and Null­Pointer­Exception 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 like Integer.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. Not­Found­Exception would be a checked exception, and that's why the signature ends throws Not­Found­Exception.
  • 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 Not­Establish­Exception, 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 StackOverflow­Error and OutOfMemory­Error. For some reason Assertion­Error 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 the throws 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 the RuntimeException and Error 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 Pointsouthward 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 unchecked Empty­Queue­Exception when the queue is empty, considering information technology'south reasonable to expect the caller to avoid this with a telephone call like Queue.size() or Queue.isEmpty().
  • Url.getWebPage() throws a checked IOException 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 checked Not­Perfect­Square­Exception when x has no integral square root, considering testing whether ten 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 ArrayIndex­OutOfBounds­Exception 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

mosleydiddlegity.blogspot.com

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

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel