Java Exceptions: Catching and Throwing, Study notes of Data Structures and Algorithms

The concept of exceptions in java programming. It covers the purpose of exceptions, the difference between checked and unchecked throwables, and how to catch and throw exceptions. The document also includes examples of exception handling using the 'try', 'catch', and 'throw' statements.

Typology: Study notes

2010/2011

Uploaded on 10/29/2011

jokerxxx
jokerxxx 🇺🇸

4.3

(36)

330 documents

1 / 2

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
09/29/10
19:22:37 1
14
CS 61B: Lecture 14
Wednesday, September 29, 2010
Today’s reading: Sierra & Bates, pp. 315-338.
EXCEPTIONS
==========
When a run-time error occurs in Java, the JVM "throws an exception," and the
result is an error message. Oddly, an exception is a Java object (named
Exception), and you can prevent the error message from printing and the program
from terminating by "catching" the Exception that Java threw.
Purpose #1: Surviving Errors
-----------------------------
By catching exceptions, you can recover from an unexpected error. For
instance, if you try to open a file that doesn’t exist or that you aren’t
allowed to read, Java will throw an exception. You can catch the exception,
print an error message, and continue, instead of letting the program crash.
try {
f = new FileInputStream("˜cs61b/pj2.solution");
i = f.read();
}
catch (FileNotFoundException e1) {
System.out.println(e1);
}
catch (IOException e2) {
f.close();
}
What does this code do?
(a) It executes the code inside the "try" braces.
(b) If the "try" code executes normally, we skip over the "catch" clauses.
(c) If the "try" code throws an exception, Java does not finish the "try"
code. It jumps directly to the first "catch" clause that matches the
exception, and executes that "catch" clause. By "matches", I mean that
the actual exception object thrown is the same class as, or a subclass of,
the exception type listed in the "catch" clause.
When the "catch" clause finishes executing, Java jumps to the next line of
code immediately after all the "catch" clauses.
The code within a "catch" clause is called an _exception_handler_.
If the FileInputStream constructor fails to open the file, it will throw a
FileNotFoundException. The line "i = f.read()" is not executed; execution
jumps directly to the whiny exception handler.
FileNotFoundException is a subclass of IOException, so the exception matches
both "catch" clauses. However, only one "catch" clause is executed--the first
one that matches. The second "catch" clause would execute if the first were
not present.
If the FileInputStream constructor runs without error, but the read() method
throws an exception (for instance, because the disk is faulty), it typically
generates some sort of IOException that isn’t a FileNotFoundException. This
causes the second "catch" clause to execute and close the file. Exception
handlers are often used to recover from errors and clean up loose ends like
open files.
Note that you don’t need a "catch" clause for every exception that can occur.
You can catch some exceptions and let others propagate.
Purpose #2: Escaping a Sinking Ship
------------------------------------
Believe it or not, you might want to throw your own exception. Exceptions are
the easiest way to move program execution out of a method whose purpose has
been defeated.
For example, suppose you’re writing a parser that reads Java code and analyzes
its syntactic structure. Parsers are quite complicated, and use many recursive
calls and loops. Suppose that your parser is executing a method many methods
deep within the program stack within many levels of loop nesting. Suddenly,
your parser unexpectedly reaches the end of the file, because a student
accidentally erased the last 50 lines of his program.
It’s quite painful to write code that elegantly retraces its way back up
through the method calls and loops when a surprise happens deep within a
parser. A better solution? Throw an exception! You can even roll your own.
public class ParserException extends Exception { }
This class doesn’t have any methods except the default constructor. There’s no
need; the only purpose of a ParserException is to be distinguishable from other
types of exceptions. Now we can write some parser methods.
public ParseTree parseExpression() throws ParserException {
[loops]
if (somethingWrong) {
throw new ParserException();
}
[more code]
}
}
return pt;
}
The "throw" statement throws a ParserException, thereby immediately getting us
out of the routine. How is this different from a "return" statement? First,
we don’t have to return anything. Second, an exception can fly several
stack frames down the stack, not just one, as we’ll see shortly.
The method signature has the modifier "throws ParserException". This is
necessary; Java won’t let you compile the method without it. "throws" clauses
help you and the compiler keep track of which exceptions can propagate where.
pf2

Partial preview of the text

Download Java Exceptions: Catching and Throwing and more Study notes Data Structures and Algorithms in PDF only on Docsity!

CS 61B:

Lecture 14

Wednesday, September 29, 2010

Today’s

reading:

Sierra & Bates, pp. 315-338.

EXCEPTIONS==========When

a

run-time

error

occurs in Java, the JVM "throws an exception," and the

result

is

an

error

message.

Oddly, an exception is a Java object (named

Exception),

and

you

can

prevent the error message from printing and the program

from

terminating

by

"catching" the Exception that Java threw.

Purpose

Surviving

Errors

-----------------------------By

catching

exceptions,

you can recover from an unexpected error.

For

instance,

if

you

try

to

open a file that doesn’t exist or that you aren’t

allowed

to

read,

Java

will throw an exception.

You can catch the exception,

print

an

error

message,

and continue, instead of letting the program crash.

try

f

new

FileInputStream("˜cs61b/pj2.solution");

i

f.read();

}catch

(FileNotFoundException e1) {

System.out.println(e1); }catch

(IOException

e2) {

f.close(); } What

does

this

code

do?

(a)

It

executes

the

code inside the "try" braces.

(b)

If

the

"try"

code

executes normally, we skip over the "catch" clauses.

(c)

If

the

"try"

code

throws an exception, Java does not finish the "try"

code.

It

jumps

directly to the first "catch" clause that matches the

exception,

and

executes that "catch" clause.

By "matches", I mean that

the

actual

exception object thrown is the same class as, or a subclass of,

the

exception

type

listed in the "catch" clause.

When

the

"catch"

clause finishes executing, Java jumps to the next line of

code

immediately

after all the "catch" clauses.

The

code

within

a

"catch" clause is called an exception_handler.

If

the

FileInputStream

constructor fails to open the file, it will throw a

FileNotFoundException.

The line "i = f.read()" is not executed; execution

jumps

directly

to

the

whiny exception handler.

FileNotFoundException

is a subclass of IOException, so the exception matches

both

"catch"

clauses.

However, only one "catch" clause is executed--the first

one

that

matches.

The

second "catch" clause would execute if the first were

not

present.

If

the

FileInputStream

constructor runs without error, but the read() method

throws

an

exception

(for instance, because the disk is faulty), it typically

generates

some

sort

of

IOException that isn’t a FileNotFoundException.

This

causes

the

second

"catch" clause to execute and close the file.

Exception

handlers

are

often

used

to recover from errors and clean up loose ends like

open

files.

Note

that

you

don’t

need a "catch" clause for every exception that can occur.

You

can

catch

some

exceptions and let others propagate.

Purpose #2:

Escaping a Sinking

Ship

------------------------------------Believe it or not, you might

want

to

throw

your

own

exception.

Exceptions

are

the easiest way to move program

execution

out

of

a

method

whose

purpose

has

been defeated.For example, suppose you’re

writing

a

parser

that

reads

Java

code

and

analyzes

its syntactic structure.

Parsers

are

quite

complicated,

and

use

many

recursive

calls and loops.

Suppose that

your

parser

is

executing

a

method

many

methods

deep within the program stack

within

many

levels

of

loop

nesting.

Suddenly,

your parser unexpectedly reaches

the

end

of

the

file,

because

a

student

accidentally erased the last

lines

of

his

program.

It’s quite painful to write

code

that

elegantly

retraces

its

way

back

up

through the method calls and

loops

when

a

surprise

happens

deep

within

a

parser.

A better solution?

Throw

an

exception!

You

can

even

roll

your

own.

public class ParserException

extends

Exception

This class doesn’t have any

methods

except

the

default

constructor.

There’s

no

need; the only purpose of a

ParserException

is

to

be

distinguishable

from

other

types of exceptions.

Now we

can

write

some

parser

methods.

public ParseTree parseExpression()

throws

ParserException

[loops]

if (somethingWrong)

throw new ParserException(); }[more code] } }return pt; } The "throw" statement throws

a

ParserException,

thereby

immediately

getting

us

out of the routine.

How is

this

different

from

a

"return"

statement?

First,

we don’t have to return anything.

Second,

an

exception

can

fly

several

stack frames down the stack,

not

just

one,

as

we’ll

see

shortly.

The method signature has the

modifier

"throws

ParserException".

This

is

necessary; Java won’t let you

compile

the

method

without

it.

"throws"

clauses

help you and the compiler keep

track

of

which

exceptions

can

propagate

where.

public

ParseTree

parse() throws ParserException, DumbCodeException {

[loops

and

code]

p

parseExpression();

[more

code]

} public

void

compile()

ParseTree

p;

try

p

parse();

p.toByteCode(); }catch

(ParserException e1) { }

catch

(DumbCodeException e2) { }

The

parse()

method

above shows how to define a method that can throw two (or

more)

exceptions.

Since every exception is a subclass of Exception, we could

have

replaced

the

two

exceptions with "Exception", but then the caller would

have

to

catch

all

types

of Exceptions.

We don’t want (in this case) to catch

NullPointerExceptions

or otherwise hide our bugs from ourselves.

When

parseExpression()

throws an exception, it propagates right through the

calling

method

parse()

and down to compile(), where it is caught.

compile()

doesn’t

need

a

"throws

ParserException" clause because it catches any

ParserException

that

can occur.

In this code, the "catch" clauses don’t do

anything

except

stop

the exceptions.

If

an

exception

propagates all the way out of main() without being caught, the

JVM

prints

an

error

message and halts.

Checked and Unchecked Throwables--------------------------------The top-level class of things

you

can

"throw"

and

"catch"

is

called

Throwable.

Here’s part of the Throwable

class

hierarchy.Throwable /

\

\

\

\

\

Exception

Error

\

\

IOException

RunTimeException

AssertionError

VirtualMachineError

\

\

NullPointerException

ClassCastException

OutOfMemoryError

An Error generally represents

a

fatal

error,

like

running

out

of

memory

or

stack space.

Failed "assert"

statements

also

generate

a

subclass

of

Error

called an AssertionError.

Although

you

can

throw

or

catch

any

kind

of

Throwable, catching an Error

is

rarely

appropriate.

Most Exceptions, unlike Errors,

signify

problems

you

could

conceivably

recover

from.

The subclass RunTimeException

is

made

up

of

exceptions

that

might

be

thrown by the Java Virtual

Machine,

such

as

NullPointerException,

ArrayIndexOutOfBoundsException,

and

ClassCastException.

There are two types of Throwables.

Unchecked

Throwables

are

those

a

method

can throw without declaring

them

in

a

"throws"

clause.

All

Errors

and

RunTimeExceptions (including

all

their

subclasses)

are

unchecked,

because

almost every method can generate

them

inadvertently,

and

it

would

be

silly

if

we had to declare them.All other Exceptions (besides

RunTimeExceptions)

are

checked,

which

means

that if your method might throw

one

without

catching

it,

it

must

declare

that

possibility in a "throws" clause.

Examples

of

checked

exceptions

include

IOException and almost any

Throwable

subclass

you

would

make

yourself.

When a method calls another

method

that

can

throw

a

checked

exception,

it

has

just two choices.(1)

It can catch the exception,

or

it must be declared so

that

it

"throws"

the

same

exception

itself.

The easiest way to figure out

which

exceptions

to

declare

is

to

declare

none

and let the compiler’s error

messages

tell

you.

(This

won’t

work

on

the

exams,

though.)