Bloch 9

advertisement

Effective Java, Chapter 9:

Exceptions

Items 57-65

Last modified Fall 2012

Paul Ammann

Item 57: Use Exceptions only for Exceptional Conditions

Don’t do this!

try{ int i=0; while (true) { range[i++].climb(); }

}catch(IndexOutOfBoundsException e){}

Note that code may hide unrelated exception!

Implications for API design

A well designed API must not force its clients to use exception handling for ordinary flow control

Provide state testing method instead of forcing client to catch exception.

More Item 57

Do this instead for (Mountain m: range) { m.climb(); }

Note:

(implicit) “State Testing” method: i < range.length

No possibility of unintentionally hiding

IndexOutOfBoundsException from climb()

Bottom line: Don’t use exceptions for ordinary flow control

More Item 57

How about?

try{

Iterator i = collection.iterator(); while (true) {

Foo foo = (Foo) i.next(); ...

}

}catch(NoSuchElementException e){}

 versus: for (Iterator i = collection.iterator(); i.hasNext();){

Foo foo = (Foo) i.next(); ...

}

More Item 57

Two basic options

State testing method

Doesn’t work in concurrent environment

State may change between state test and actual call

May be undesirable if state testing method is as much computation as actual call

Then, it’s better to have a distinguished return value

Distinguished return value

May not be an unused special value

Example: “null” for Object return types

Iterator next() method can legitimately return “null”

Faulty use of distinguished return value model harder to detect

Item 58: Checked vs.

Unchecked

Unchecked exceptions indicate programming errors

Precondition violations

Recovery is impossible

Checked exceptions indicate recoverable conditions

Force the caller to handle the exception

More Item 58

Use unchecked exceptions if

 client has nothing to do

OutOfMemoryException client knows better

 doesn’t need try-catch block; if-then block would suffice.

Use checked exceptions if client has some reasonable action

IOException  Calling code is correct, but exception can still be raised!

Item 59: Avoid Unnecessary

Use of Checked Exceptions

try{ obj.action(args)

}catch(SomeCheckedException e){ throw new Error (“Assertion Error”);

} // should never happen

What is the point of making a client do this?

Conditions for using checked exceptions:

Exceptional condition cannot be prevented by proper use of the API

Programmer can take some useful action

More Item 59

Standard Transformation: if (obj.actionPermitted(args)) { obj.action(args);

} else {

// Handle exceptional condition

}

Or even simply (where appropriate): obj.action(args); // Client allows call to fail

Item 60: Favor Use of

Standard Exceptions

IllegalArgumentException

- Inappropriate parameter; several special cases

NullPointerException (param null where

 prohibited)

IndexOutOfBoundsException (index param out of range)

ClassCastException

More Item 60

IllegalStateException

Object state is inappropriate for method invocation

Object may not be initialized before calling accessing its state

Special subtype: ConcurrentModificationException

Concurrent modification detected where not allowed

UnsupportedOperationException

Object does not support the method

Substitution principal

More Item 60

Reasons to use standard exceptions:

Using your API is easier

Reading your programs is easier

Performance advantage (relatively minor)

No additional namespace to manage

Note that standard Java exception list is more than the 6 mentioned in Bloch

Item 61: Throw Exceptions

Appropriate to the Abstraction

Propagated exceptions may make no sense

Higher layers should translate lower level exceptions

// Bad example : public int min (int[] a) { int minVal = a[0]; // Bad: Throws IndexOutOfBoundsException for (int val: a) {if (val < minVal) minVal = val;} return minVal;

}

More Item 61:

Exception Chaining Transformation: try {

// Use low level abstraction to satisfy contract

} catch (LowerLevelException cause) { throw new HigherLevelException (cause);

}

Achieves 2 very different goals

Gives client exception at expected level of abstraction

Also preserves low level detail for failure analysis

Item 62: Document All Exceptions

Thrown by Each Method

Checked Exceptions:

Declare (required by compiler)

And Document (with @throws tag in JavaDoc)

Unchecked Exceptions:

Document (with @throws tag in JavaDoc)

Don’t shortcut with superclass exceptions

Example: Don’t catch “Exception” instead of

NullPointerException

Ok to document common exceptions at class level

Example: “All methods in class throw NullPointerException if a null object reference is passed in any parameter”

Item 63: Include Failure-Capture

Information in Detail Messages

Uncaught exceptions result in printing of stack trace, including “detail” messages

These messages should contain values of all parameters that “contributed to the exception”

In other words, include relevant state information

Example: IndexOutOfBoundsException includes upper bound, lower bound, and offending index

Item 64: Strive for Failure

Atomicity

Failure atomicity:

A failed method invocation should leave the object in the state that it was in prior to the invocation

Ways to achieve this effect:

Design immutable objects

Check parameters for validity before performing the operation

Order the computation – parts that fail come before modification

Write recovery code – cause the object to roll back its state

Perform the operation on a temporary copy of the object

More Item 64:

public int addMax(List<Integer> list, Integer x) throws …

//pre: true

//post: if x is not max w.r.t. list, throw IAE

// else append x to list

Don’t throw exception in between modifications to state variables

Procedure should have an atomic effect throw exception in the beginning if you are not sure you can pull it off

More Item 64

public Object pop() throws … {

//Requires: this != EmptyStack

//Modifies: this

//Effects: pops this and returns top

Object result = elements[--size]; elements[size] = null; return result;

} // Note: Client can corrupt state – oops!

More Item 64

public Object pop() throws … {

//Requires:

//Modifies: this

//Effects: If this empty throw ISE

// else pop this and returns top if (size == 0) { throw new ISE(…);

Object result = elements[--size]; elements[size] = null; return result;

} // Note atomic execution, normal or exception

Item 65: Don’t Ignore

Exceptions

Programmers should never leave a catch block empty

Its easy to ignore exceptions, but don’t!

try{

...

}catch(Exception e){

} // empty catch block wont raise complaints

// from compiler! Don’t do this!

More Item 65

If its empty, its highly suspect

The purpose of exception is to force programmers handle exceptional conditions

At least have a comment which explains why its ok to ignore this exception

Download