Вы находитесь на странице: 1из 32

Session 9

EXCEPTIONS
Agenda

Understanding exceptions
Syntax
How try/catch/throw works
finally and try-with-resources
Types of exceptions
Effectively using exceptions
Best practices
Stacktraces (how to read them)
Understanding exceptions

Error handling
Programs will encounter errors while
they run (at runtime)
Guaranteed
Whats an error?
Anything that prevents your program to
proceed further: invalid input, missing
input, insufficient resources (memory,
disk space), system errors, etc.
Understanding exceptions

Why? Robustness
Useful programs are resilient to errors
Either handle the errors (alternate route) or
report them (so the user can debug)
Usually programs are composed by multiple
modules (or libraries)
A robust program must take errors into account
when they specify how modules interact
Tell what errors might be reported by the module and for
what reason
Understanding exceptions
Old Way

Methods return an error code


or set a global variable
This is an error prone approach
Developers forget to check the
result or the global flag
Not defined/enforced by the
language, different libraries have
their own approach
Understanding exceptions
Java Way

Unified mechanism, enforced by the compiler


Errors are reported by methods through a dedicated
mechanism, separated from the return value
When an exception is thrown the JVM executes a very
specific sequence of steps in order to give your
program a chance to recover
Main concepts:
Throwing an exception: the way your code tells the JVM that it
encountered an error
Catching an exception: the way your code tells the JVm that it
wants to handle an error (print a message or take an
alternate route)
Syntax

Throwing an exception

throw new IllegalArgumentException("foo should not be


null");

Things to note:
1. The exception itself is just a normal Java object
created with new.
2. Therefore it can have parameters
3. When the program encounters such a statement
the JVM exception handling mechanism takes
control of what will be executed next
Syntax

Catching exceptions

try{
//some code that throws exceptions
}catch(NumberFormatException | IllegalStateException e){
// handle both exceptions
}catch (IllegalArgumentException e){
// handle NPE
}

Things to note:
1. The code that throws exceptions needs to be
surrounded by a try/catch block
2. Different exception types can be handled
independently
3. The order of catch clauses matters
How throw/try/catch works

public static void main(String[] args) {


try {
ageInMonths(Integer.parseInt(args[0]));
} catch (NumberFormatException e) {
System.out.println("first program argument needs to be an int");
}catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}

static int ageInMonths(int age) {


if (age < 0) {
throw new IllegalArgumentException("age should be >= 0");
}
return age * 12;
}
How throw/try/catch works

What happens when throw is called?


The exception object is created
The JVM exception handling mechanism takes
control and decides the next line of code to be
executed
It looks for the closest catch clause that handles
the exception:
First in the current method
Then in the calling method
And so on up the call chain
If none is found (even in main) the program exists
A catch handles exceptions of the declared type
and all its subclasses
finally

Used to always execute a block of code


Regardless of whether exceptions were thrown or not
finally

BufferedReader r = new BufferedReader(new FileReader("text.txt"));


try {
String firstLine = r.readLine();
} catch (IOException e) {
System.out.println("Cannot read first line from text.txt: +
e.getMessage());
} finally {
r.close();
}
try-with-resources

The pattern of closing resources in finally was


often used so Java introduced a special syntax for
it
try (BufferedReader r = new BufferedReader(new FileReader("text.txt"))) {
String firstLine = r.readLine();
} catch (IOException e) {
System.out.println("Cannot read first line from text.txt: +
e.getMessage());
}

The condition is that all variables declared with try


implement the java.lang.AutoCloseable interface
Types of exceptions
Hierarchy

Exceptions hierarchy
Types of exceptions
Checked vs. Unchecked

All exceptions derived directly or


indirectly from Exception (excluding
RuntimeException) are called
checked exceptions
Those derived form RuntimeException
(actually all the rest) are called
unchecked
Who checks them? The compiler.
Types of exceptions
Checked vs. Unchecked

How checked exceptions are


checked?
Compiler enforced rule: methods
should either handle checked
exceptions (with catch) or declare
that they pass them further up the
call chain (with a special syntax)
Types of exceptions
Checked vs. Unchecked

throws syntax

public static void main(String[] args) throws Exception {


System.out.println(circleArea(10.5));
}

public static void main(String[] args) {


try {
System.out.println(circleArea(10.5));
} catch (Exception e) {
System.out.println("Cannot calculate area: " + e.getMessage());
}
}

static double circleArea(double radius) throws Exception {


if(radius < 0){
throw new Exception("radius should be positive");
}
return Math.PI * radius * radius;
}
Types of exceptions
Custom Exceptions

Custom exception types


Sometime you need to report a
specific kind of error that was not
foreseen by the creators of Java
Since an exception is just a normal
Java object derived (directly or
indirectly) from Throwable, you can
create your own exception types
Types of exceptions
Custom Exceptions

A classic example of a checked exception is a validation error:


class ValidationException extends Exception {
public ValidationException(String message) {
super(message);
}
}
static int parseAge(String age) throws ValidationException {
int value;
try {
value = Integer.parseInt(age);
}catch (NumberFormatException e){
throw new ValidationException("should be an int");
}
if(value < 0 || value > 150) {
throw new ValidationException("should be between 0 and 150 inclusive");
}
return value;
}
public static void main(String[] args) {
try {
int age = parseAge(args[0]);
} catch (ValidationException e) {
System.out.println("Invalid age argument: " + e.getMessage());
}
}
Best practices

Avoid checked exceptions


Checked exceptions are good in theory,
practice proved otherwise
People were forced to deal with
exceptions that could not be recovered
As a result of using checked exceptions for
things that should have been (like missing
resources or syntax errors) unchecked:
IOException, SQLException
Best practices

Avoid checked exceptions


Transform to unchecked
void processFile(String file) /* throws IOException */ {
try {
String firstLine = readFirstLine(file);
} catch (IOException e) {
//what to do here?
}
}

public static void readFirstLine() throws IOException {


try (BufferedReader r = new BufferedReader(new FileReader("text.txt"))) {
String firstLine = r.readLine();
}
}
Best practices

Dont use exceptions for flow control


Makes your code harder to
understand (violates the Principle of
least astonishment)
Exceptions are sometime expensive
(performance wise) (modern
compilers get over it)
Best practices

Dont use exceptions for flow control


//bad
boolean verifyCnp(String cnp){
try {
char s = cnp.charAt(0);
//more code to verify
}catch (NullPointerException | IndexOutOfBoundsException e) {
throw new IllegalArgumentException("cnp should be exactly 13 digits long");
}
}

//good
boolean verifyCnp(String cnp){
if(cnp == null || cnp.length() != 13) {
throw new IllegalArgumentException("cnp should be exactly 13 digits long");
}
char s = cnp.charAt(0);
//more code to verify
}
Best practices

How to log exceptions


The application log is some storage (usually
a file) where an application can write
messages during its runtime for
maintenance and debugging purposes
Key abstractions:
A message
With a specific severity level
Is written by a logger
Rule for effective exception logging:
Establish a central place where to log
Bubble up exceptions to that place
Best practices

private static Logger logger = Logger.getLogger("my.class.fqn");


public static void main(String[] args) {
logger.info(start main");
try {
String file = "read it from UI";
readFirstLine(file);
//more code that throws exceptions
} catch (Exception e) {
logger.log(Level.SEVERE, "Error during run", e);
}
logger.info(end main");
}

public static void readFirstLine(String file) {


try (BufferedReader r = new BufferedReader(new FileReader(file))) {
String firstLine = r.readLine();
} catch (IOException e) {
//do not log here
throw new RuntimeException(cannot read first line from file " + file, e);
}
}
Best practices

Configure logging:
Create a file logging.properties
handlers= java.util.logging.FileHandler,java.util.logging.ConsoleHandler
.level=INFO
java.util.logging.FileHandler.pattern=c:/work/sci-exceptions/exceptions.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

Start your program with


-Djava.util.logging.config.file=logging.properties
Best practices

Dont use empty catch blocks


Minimum acceptable: a comment
explaining why its empty

try{
//code that reads from a file }
catch(IOException e){
//there is a _very_ good reason I ignore
this IOException: here it is
}
Best practices

When to create custom exception


types
Prefer standard exceptions
Create custom exception types when
you want to report a specific error in
your application that you will handle
in some other part/module
Best practices

When to use custom exceptions


static class BookingCapacityExceededException extends RuntimeException { }

void tryBook(){
try{
book();
}catch(BookingCapacityExceededException e){
//handle it
}
}

Booking book(){
if(!isCapacityAvailable()) {
throw new BookingCapacityExceededException();
}
//booking code
}
Best practices

Dont catch Throwable


Because you want to be specific and
not catch exceptions that you dont
want to
Catching Errors is most of a time a
bad idea since they are end-of-the-
road exceptions
Stacktraces

class ContactRepository {
String file;
ContactRepository(String file) { this.file = file; }

void saveContact(String name, String email){


String row = name + "," + email + "\n";
writeRow(row);
}
void writeRow(String row) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter(file, true));
out.write(row);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
ContactRepository repo = new ContactRepository(x:\\file.csv");
repo.saveContact(Adrian", 123");
}
Bibliography

Thinking in Java: Error Handling with


Exceptions
https://docs.oracle.com/javase/tutorial/
essential/exceptions/
http://www.javacodegeeks.com/
2013/07/java-exception-handling-
tutorial-with-examples-and-best-
practices.html
http://beginnersbook.com/2013/04/java-
exception-handling/

Вам также может понравиться