Head First Java Chapter 11 Summary — Risky Behavior

Manisha Ekanayake
7 min readJul 16, 2022

--

The purpose of this article is to highlight the key ideas covered in chapter 11.

*Hierarchy of Java Exception classes

The class at the top of the exception class hierarchy is the Throwable class, which is a direct subclass of the Object class. Exception and Error are two of Throwable’s direct subclasses. The Exception class is used for exception conditions that the application may need to handle and also The Error class is used to indicate a more serious problem in the architecture and should not be handled in the application code. The hierarchy of Java exception classes is shown below.

Here we can see Exception and Error classes are subclasses of the Throwable class. Throwable is not an interface. and Throwable class extend Object class. Errors are what we cannot handle.

*Types of Java Exceptions

There are mainly two types of exceptions: Checked exception & Unchecked exception . An error is considered as the unchecked exception. However, according to Oracle, there are three types of exceptions namely:

  1. Checked exception

The classes that directly inherit the Throwable class except RuntimeException and Error are called as checked exceptions. Checked exceptions are checked at compile-time. IOException, SQLException, are a few examples.

2. Unchecked exception

The classes that inherit the RuntimeException are called as unchecked exceptions. Unchecked exceptions are not checked at compile-time, but they are checked at runtime. ArithmeticException & NullPointerException are few examples of unchecked exception.

3. Errors

Error is irrecoverable. OutOfMemoryError, AssertionError are some example of errors .

The exception-handling mechanism in Java is a clean, well-lighted way to handle “exceptional situations” that occur during runtime. It enables us to place all the error-handling code in convenient location (one easy-to-read place).

*How To Handle Exceptions

We can use the try, catch, finally, throw and throws blocks or keywords to handle the exception

*Flow control in try/catch blocks

The “try” keyword is used to specify a block where we should place an exception code. It means we can’t use try block alone. The try block must be followed by either catch or finally. The exception is dealt with using the “catch” block. We cannot use catch block alone; try block must come before it. “Finally ”block could be used to follow it later.

One of two things can happen when we call a risky method.

  1. Risky method either succeeds, and the try block completes.
  2. The risky method throws an exception back to your calling method.

Let’s see examples to understand try/catch

try { 
Foo f = x.doRiskyThing();
int b = f.getNum();


} catch
(Exception ex) {
System.out.println(“failed”);
}
System.out.println(“We made it!”);

If the try succeeds doRiskyThing() does not throw an exception. First, the try block runs, then the code below the catch runs, and also the code in the catch block never runs.

try { 
Foo f = x.doRiskyThing();
int b = f.getNum();

} catch
(Exception ex) {
System.out.println(“failed”);
}
System.out.println(“We made it!”);

If the try fails (because doRiskyThing() does throw an exception). The try block runs, but the call to doRiskyThing() throws an exception, so the rest of the try block doesn’t run. The catch block runs, then the method continues on.

*Finally Block

The “finally” block is used to execute the necessary code of the program. It is executed whether an exception is handled or not.

Let’s see an examples to understand finally block,

try { 
turnOvenOn();
x.bake();

} catch (BakingException ex) {
ex.printStackTrace();

} finally {
turnOvenOff();
}

Without finally block, we have to put the turnOvenOff() in both the try and the catch because you have to turn off the oven no matter what. A finally block lets you put all the important cleanup code in one place instead of duplicating it like below:

try { 
turnOvenOn();
x.bake();
turnOvenOff();

} catch (BakingException ex) {
ex.printStackTrace();
turnOvenOff();
}
  • If the try block fails (an exception):flow control immediately moves to the catch block. The finally block starts once the catch block is finished. The rest of the method continues on when the finally block completes.
  • If the try block succeeds (no exception):flow control skips over the catch block and moves to the finally block. The rest of the method proceeds after the finally block has finished.
  • If the try or catch block has a return statement: finally block will still run. Flow jumps to the finally, then back to the return.

*Can a method throw more than one exception?

Yes, If necessary, a method can throw more than one exception. But a method’s declaration must declare all checked exceptions it can throw, however if two or more exceptions share a superclass, the method can declare the superclass.

*Catching Multiple Exceptions

The compiler will ensure that all checked exceptions thrown by the method we are calling have been handled. The catch blocks should be placed one on top of the other under the try. Sometimes it affects what order the catch blocks are stacked.

What happens in each catch block is described in the example below. if doLuandry() throws a PantsException, it moves to that catch block where it can be handled. If it throws a LingerException, it moves to that catch block where it can also be handled.

*Using these kinds of different catch block for each exception, it means that handle each exception uniquely. Alos can use a super type exception in the catch block.

catch (Exception e){

//recover code

}

*Multiple catch blocks must be ordered from smallest to biggest.

A ShirtException catch is big enough to take a TeeShirtException. A ClothingException is even bigger (there are more things that can be referenced using a ClothingException type). It can take an exception of type ClothingException(), and any ClothingException subclasses. The mother of all catch arguments is type Exception; it will catch any exception, including runtime (unchecked) exceptions.

*can’t put bigger Exception above smaller Exception.

Size matters when we have multiple catch blocks. The one with the biggest has to be on the bottom. Otherwise, the ones with smaller Exceptions are useless. we you can put it, but it won’t compile. Catch blocks are not like overloaded methods where the best match is picked. With catch blocks, the JVM simply starts at the first one and works its way down until it finds a catch that’s broad enough to handle the exception.

And also when the first catch block is catch(Exception ex), the compiler knows there’s no point in adding any others and it won’t compile it.

try { 
laundry.doLaundry();

} catch(Exception ex) { //Can't put catch(Exception ex)block 1st
// recovery code
} catch(TeeShirtException tex) {
// recovery code
} catch(LingerieException lex){
// recovery code
}

*Throw Block

When we don’t want to handle an exception, we can duck it by declaring it. When we call a risky method, the compiler needs to acknowledge it. Most of the time, that means wrapping the risky call in a try/ catch. But we have another alternative, duck it and let the method that called you catch the exception. We have to do is declare that we throw the exceptions.

public void laundry() throws BadException{
// call risky method without a try/catch
laundry.doLaundry();
}

Here we don’t REALLY throw it, but since we don’t have a try/catch for the risky method we call, risky method. Because now, whoever calls ,has to deal with the exception.

*Exception Rules

  1. Cannot have a catch or finally without try block
//The below code is not legalvoid go() { 
Foo f = new Foo();
f.foof();
catch(FooException ex) { }
}

2. Cannot put a code between the try and the catch

// Not legal ! can’t put code between the try and  the catchtry { 
x.doStuff();
}
int y = 43;
} catch(Exception ex) { }

3. A try MUST be followed by either a catch or a finally

// LEGAL because have a finally, even  though there’s no catch.But cannot have a try by itselftry { 
x.doStuff();
} finally {
// cleanup
}

4. A try with only a finally (no catch) must still declare the exception

//A try without a catch  doesn’t satisfy the  handle or declare lawvoid go() throws FooException { 
try {
x.doStuff();
} finally { }
}

*Bullet Points

· A method can throw an exception when something fails at runtime.

· An exception is always an object of type Exception. (Which, as you remember from the polymorphism chapters means the object is from a class that has Exception somewhere up its inheritance tree.)

· The compiler does NOT pay attention to exceptions that are of type Runtime Exception. A Runtime Exception does not have to be declared or wrapped in a try/catch (although you’re free to do either or both of those things)

· All Exceptions the compiler cares about are called ‘checked exceptions’ which really means compiler-checked exceptions. Only Runtime Exceptions are excluded from compiler checking. All other exceptions must be acknowledged in your code, according to the rules.

· A method throws an exception with the keyword throw, followed by a new exception object: throw new NoCaffeineException();

· Methods that might throw a checked exception must announce it with a throws Exception declaration.

· If your code calls a checked-exception-throwing method, it must reassure the compiler that precautions have been taken.

· If you’re prepared to handle the exception, wrap the call in a try/catch, and put your exception handling/recovery code in the catch block.

If you’re not prepared to handle the exception, you can still make the compiler happy by officially ‘ducking’ the exception. We’ll talk about ducking a little later in this chapter

--

--