exceptions, errors, and all that gunk (for sure this time)

24
Exceptions, Errors, and all that gunk (for sure this time)

Post on 20-Dec-2015

218 views

Category:

Documents


1 download

TRANSCRIPT

Exceptions, Errors, and all that gunk

(for sure this time)

Happy Vernal Equinox!

Administrivia•Wed (Mar 23): R2 due

•2 weeks from today (Apr 4): P2 rollout due

Testing Tips III•Design for testability

•Build in instrumentation points

•Methods (possibly protected) that allow monitoring of state/results

•Debug/test-specific code

•Test rigs (JUnit, java.awt.robot, etc.)

•Recordable/repeatable test results

•toString(), other formatted output

•Static debug printer classes

•E.g., output of syntactic/semantic analyzers in P2

Commandment VIIf a function be advertised to return an error code in the event of difficulties, thou shalt check for that error code, yea, even though the checks triple the size of thy code and produce aches in thy typing fingers, for if thou thinkest “it cannot happen to me”, the gods shall surely punish thee for thy arrogance.

-- The Ten Commandments for C

programmers

Expecting the unexpected•Huge fraction of code (30%? 50%?

More?) is handling unexpected cases

•Problem is: code that detects unexpected, doesn’t always know what to do about it

•Idea of Exceptions, et al. is to move handling of errors out to appropriate place to deal with them

•Nice idea in principle...

•Very hard to get right in practice

Ideal model•throw + try/catch/finallypublic int fooMethod(int a) {

if (a<0) {throw new IllegalArgumentException(”a must “ +

“be non-negative, not a=” + a);}// etc...

}

public void barMethod() {try {

fooMethod(-37);}catch (IllegalArgumentException e) {

// do something about it...}

}

Nastier in practice•“Checked” vs. “unchecked” exceptions

•“Checked”==compiler checks to make sure you take responsibility for it

•Explicit catch

•Declare that it passes out of the methodpublic void myLoader(String fname) throws IOException{

FileReader in=new FileReader(fname);// do stuff to inin.close();

}

•“Unchecked”==you’re all on your own

•Compiler doesn’t care if you catch/declare

•E.g., IllegalArgumentEx., ArrayIndexOutOfBoundsEx.

What’s the “real” diff?•How does the compiler know which is

which?

•How does the compiler know which is which?

•Javac doesn’t do checks for two families of exceptions:• Error (and subclasses)• RuntimeException (& etc.)

What’s the “real” diff?

When to use them•Can make an unchecked exception by

extending Error or RuntimeException

•But... Do you want to?

•Issue: Checked exceptions tell you a lot about how class/interface/type works

•E.g., java.io.* methods mostly throw checked exceptions

•Tells you about their failure modes

•Want to use checked exceptions whenever you (practically) can

When is it practical?•Some books say “Always use checked

exceptions”

When is it practical?•Some books say “Always use checked

exceptions”

•Wrong.

When is it practical?•Checked exceptions are good when the receiving

code can actually do something about the problem

•IOExceptions

•Can’t open file => Ask user for new file name

•File ends prematurely => close file, discard loaded data, ask for new file, etc.

•PrintException

•Printer out of paper => ask user to add paper

•ParseException

•Unexpected/missing token => warn user about syntax error/corrupted file

What about Runtime?•RuntimeException better for things that

code can’t do much about

•Programming errors

•Precondition errors (if (a<0) { throw... })

•“Impossible” errors (“This shouldn’t happen”)

•Stuff that may or may not be b/c of structure of code (may be related to user input)

More RuntimeException•Even if unchecked, still useful to put in

throws clause sometimes

•Always good to document in API

•Some books say: “Never extend RuntimeException”

•Wrong.

•But do be careful

•Not an excuse to be lazy!

Error•java.lang.Error used to indicate problem in Java

interpreter (JVM)

•Mostly stuff that’ll cause your program to die a hideous, agonizing, painful (but thankfully quick) death anyway

•Class loader problems

•Bugs in the JVM (!)

•Circular code definitions (that sneak past javac)

•Out of memory

•Very rare that you’ll generate one by hand

•Mostly, do similar functions w/ RuntimeException

Assertions•assert: “conditional” exceptions

•Can turn off/on all checks in code

•java -ea (“enable assertions”) to turn on assertion checks

•Enable for debugging, disable for shipping

•Used to check preconditions and fundamental design problems in code

•Stuff that should never happen

•Stuff that should be cleaned up before code ships

Assertions, cont’d•Good for pre/post condition checks and

logic errorspublic double sqrt(double d) {

assert d>=0 : “d=” + d;// calculate s=square root of dassert s>=0 : “s=” + s;return s;

}// elsewhere...

switch (x) {case ‘a’: // do ‘a’ thing; breakcase ‘b’: // do ‘b’ thing; breakdefault: assert false : “x=” + x;

Error message text•Note: 2 possible “consumers” of error message

text in exception/error/assertion arguments:

•Developer

•User

•They have very different knowledge and needs

•Developer: knows a lot about how program works

•Needs to know: what went wrong & how to fix it

•User: knows nothing about how program works (and doesn’t want to)

•Needs to know: how to recover from whatever went wrong

Error msgs, cont’d•Unfortunately, Java does not distinguish 2 cases

•For your progs, you can (conceivably) extend Exception, etc. to have 2 args -- a programmer arg and a user arg

•User should never see raw exception (i.e., program crash and stack dump) -- should only see nice msg and useful UI w/ recovery instructions (or graceful shutdown)

•Catch exceptions and present content nicely to user

•Note: asserts should never be seen by user anyway, so msg can be more terse (nonexistant)

Exceptions & recursion•Recursive routines (e.g., parsing) is a

great place to use exception mechanism

•Can throw from very bottom of recursive stack and catch at top

•Or, use intermediate catchs along the way to recover partial result

•E.g., consume tokens until you know you’re back into a recognizable part of the parse

•Can use finally to “unwind” partial results (save state, close files, etc.) as error propagates up the stack

Do-s•Use checked exceptions when you possibly can

•Provide useful messages to exceptions

•Think about who’s seeing the msg

•Provide erroneous data when you can

•new ZurkException(“a must be >0”);

•new ZurkException(”a must be >0, “ +“not a=” + a);

•Use assert for argument validation when possible

•Use RuntimeException for other code validation/when assert not practical

•Document even your unchecked exceptions!

Don’t-s•throw new Exception(“some lame message”)

•Extend Throwable (no need)

•Use exceptions for “normal” control flowint i=0;int[] a=new int[10];try {

while (true) {doSomething(a[i++]);

}} catch (ArrayIndexOutOfBoundsException ex)

•Eeeeeeeevil! (Why?)