Errors and Exception
The challenge of handling the not-so-happy-path
public int div(int a, int b)
{
// how to communicate illegal division by 0?
return a / b;
}
public Reader open(String path)
{
// what if the file does not exist
return new FileReader(new File(path));
}
public Date parse(String date, Locale locale)
{
// how to tell the caller that the input was illegal?
// there are three types of illegal:
// null, not parsable, and not parsable for the locale
}
Types of problems we might encounter
This list is not an official error type list.
The old way of doing things
What Java offers to deal with problem types
throws
throw
Raise a Throwable
Throwable
a this point in the code
/**
* This method raises a runtime exception
*/
public String trouble(final String foo)
{
if (foo == null)
{
// raise without explaination
throw new NullPointerException();
}
if (foo.length() == 0)
{
// raise with explaination
throw new NullPointerException("Empty string given");
}
return foo + System.currentTimeMillis();
}
Exception in thread "main" java.lang.NullPointerException
at Test.trouble(Test.java:12)
at Test.main(Test.java:26)
Exception in thread "main" java.lang.NullPointerException: Empty string given
at Test.trouble(Test.java:12)
at Test.main(Test.java:26)
Declares that an exception has to be dealt with
Throws
as part of message declaration
/**
* Our checked(!) exception
*/
public class BarException extends Exception
{
...
}
/**
* I will be called
*/
public void foo() throws BarException
{
throw new BarException();
}
/**
* The caller
*/
public void callFoo()
{
try
{
foo();
}
catch(final BarException e)
{
// compiler enforces this
}
}
/**
* The caller version 2
*/
public void callFoo2() throws BarException
{
foo();
}
Serious trouble is indicated
throws
needed or recommended
java.lang.Error
/**
* Predefined errors
*/
AnnotationFormatError, AssertionError, AWTError,
CoderMalfunctionError, FactoryConfigurationError,
FactoryConfigurationError, IOError, LinkageError,
SchemaFactoryConfigurationError, ServiceConfigurationError,
ThreadDeath, TransformerFactoryConfigurationError,
VirtualMachineError
Seriously, hands off these errors.
Problems you have to and should handle
Throws
Throws
but compiler does not carePick wisely, once you made the call, the type cannot be changed anymore.
Handle an exception
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
// more code that is not executed when the exception is raised
}
catch(final FileNotFoundException e)
{
// do your stuff here
// try to avoid other exceptions
}
// this code runs for sure
String a = "hi";
}
Deal with multiple exceptions differently
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
// more code that is not executed when the exception is raised
throw new IOExcpeption();
}
catch (final FileNotFoundException e)
{
// do your stuff here
// try to avoid other exceptions
}
catch (final IOException e)
{
// do your stuff here
// try to avoid other exceptions
}
// this code runs for sure
String a = "hi";
}
Handle exceptions the same way
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
// more code that is not executed when the exception is raised
}
catch (final FileNotFoundException | final InvalidHandleException e)
{
// do your stuff here
// try to avoid other exceptions
}
}
Nice addition to Java, not often used yet.
Code that should run regardless
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
// more code here that might not run
}
finally
{
// this will always run
}
}
Catch and clean
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
// code that is not executed when the exception is raised
}
catch (final FileNotFoundException e)
{
// do special stuff for the exception case
}
finally
{
// this will always run
// don't raise other exceptions
// this will run last!
}
}
Something special about return
public void test()
{
try
{
InputStream is = new FileInputStream(new File("foo.txt"));
return; // I am not the last statement of this execution!
}
catch (final FileNotFoundException e)
{
// do special stuff for the exception case
}
finally
{
// this will always run
// and the execution will happen despite the return
}
}
Less code to deal with
java.lang.AutoCloseable
for the resource in question// Old School
public void test()
{
InputStream is = null;
try
{
is = new FileInputStream(new File("foo.txt"));
}
catch (final FileNotFoundException e)
{
// do special stuff for the exception case
}
finally
{
if (is != null)
{
is.close(); // can raise an exception!
}
}
}
// The New Kid
public void test()
{
try(InputStream is = new FileInputStream(new File("foo.txt")))
{
}
catch (final FileNotFoundException e)
{
// do special stuff for the exception case
}
}
Include more resources
// The New Kid
public void test()
{
try(
InputStream is = new FileInputStream(new File("foo.txt"));
OutputStream os = new OutputStream(new File("bar.txt"));
)
{
// your I/O code here
}
catch (final FileNotFoundException e)
{
// do special stuff for the exception case
}
// This is the virtual finally block.
// Java will auto-close "os" first
// "is" last
}
Communicating the exception after handling
public void test() throws FoobarException
{
try
{
// do all the stuff
throw new FoobarException();
}
catch(final FoobarException e)
{
// do your error handling here
// let the others know what the problem is
throw e;
}
}
Exception in thread "main" FoobarException
at Test.test(Test.java:30)
at Test.main(Test.java:43)
An exception in an exception
public void test()
{
try
{
// do all the stuff
throw new FoobarException();
}
catch(final FoobarException e)
{
// do your error handling here
// let the others know what the problem is
throw new RuntimeException(e);
}
}
Exception in thread "main" java.lang.RuntimeException: FoobarException
at Test.test(Test.java:37)
at Test.main(Test.java:43)
Caused by: Test$FoobarException
at Test.test(Test.java:30)
... 1 more
Apply caution!
Best practises
Everything has a price
fillInStackTrace
method and avoid the cost of stack collection; this will suppress the location/origin of the exceptionhttp://java-performance.info/throwing-an-exception-in-java-is-very-slow/