

Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
A part of the lecture notes for cs 61b at the university of california, berkeley. It covers the topics of exceptions, specifically the 'finally' keyword and exception constructors. Additionally, it introduces generics and their use in java, as well as field shadowing in subclasses. Useful for university students studying computer science, particularly those enrolled in cs 61b or similar courses.
Typology: Study notes
1 / 2
This page cannot be seen from the preview
Don't miss anything!


Lecture 15
Friday, October 1, 2010
Today’s
reading:
Sierra & Bates, pp. 189, 283.
(continued)
==========The
"finally"
keyword
finally
clause
can
also be added to a "try."
try
statementX;return
catch
(SomeException e) {
e.printStackTrace();return
finally
f.close();return
If
the
"try"
statement
begins to execute, the "finally" clause will be executed
at
the
end,
no
matter
what happens.
This example (which is contrived) always
returns
never
or
If
statementX
causes
a
SomeException, the exception is caught, the "catch"
clause
is
executed,
and
then the "finally" clause is executed.
If statementX
causes
some
other
class
of exception, the "finally" clause is executed
immediately,
then
the
exception continues to propagate down the stack.
"finally"
clauses
are
used to do things that need to be done in both normal and
exceptional
circumstances.
(Again, closing files is an example.)
In
the
example
above,
we’ve invoked the method "printStackTrace" on the
exception
we
caught.
When an exception is created, it takes a snapshot of the
stack,
which
can
be
printed later.
It
is
possible
for
an
exception to occur in a "catch" or "finally" clause.
An
exception
thrown
in
a
"catch" clause will terminate the "catch" clause, but the
"finally"
clause
will
still get executed before the exception goes on.
An
exception
thrown
in
a
"finally" clause replaces the old exception, and
terminates
the
"finally" clause and the method immediately.
However...you
can
put
a
"try" clause inside a "catch" or "finally" clause,
thereby
catching
those
exceptions as well.
Exception
constructors
----------------------By
convention,
most
Throwables (including Exceptions) have two constructors.
One
takes
no
parameters, and one takes an error message in the form of a
String.
class
MyException
extends Exception {
public
MyException() { super(); }
public
MyException(String s) { super(s); }
The
error
message
will
be printed if it propagates out of main(), and it can be
read
by
the
Throwable.getMessage() method.
The constructors usually call the
superclass
constructors, which are defined in Throwable.
GENERICS========Suppose you’re using a list
of
Objects
to
store
Strings.
When
you
fetch
a
String from the list, you have
to
cast
it
back
to
type
"String"
before
you
can
call the methods exclusive
to
Strings.
If
somehow
an
object
that’s
not
a
String got into your list,
the
cast
will
throw
an
exception.
It
would
be
nice
to have the compiler enforce
the
restriction
that
nothing
but
Strings
can
ever
get into your list in the first
place,
so
you
can
sleep
at
night
knowing
that
your family is safe from a
terrible
ClassCastException.
So Java offers generics,
which
allow
you
to
declare
general
classes
that
produce specialized objects.
For
example,
you
can
create
an
SList
for
Strings
only, and another SList for
Integers
only,
even
though
you
only
wrote
one
SList class.
To specify the
class,
SList
takes
a
type_parameter.
class SListNode
T item;public SListNode
n)
item = i;next = n; } } public class SList
SListNode
item)
head = new SListNode
head);
} You can now create and use
an
SList
of
Strings
as
follows.
SList
SList
of
Integers
by
using
"SList
in
the
declaration and constructor.The advantage of generics here
is
that
the
compiler
will
ensure
at
compile-
time that nothing but Strings
can
ever
enter
your
SList
so
there
will
be no nasty surprises at run
time.
Generics are a complicated
subject.
Consider
this
to
be
a
taste
of
them;
hardly a thorough treatment.
Sun
has
a
much
longer
tutorial
at
http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
Although Java generics are
superficially
similar
to
templates,
there’s
a
crucial difference between
them.
In
the
example
above,
Java
compiles
bytecode
for only a single SList class.
This
SList
bytecode
can
be
used
by
all
different object types.
It
is
the
compiler,
not
the
bytecode
itself,
that
enforces the fact that a particular
SList
object
can
only
store
objects
of
a
particular class.
Conversely,
recompiles
the
SList
methods
for
every
type
that you instantiate SLists
on.
The
disadvantage
is
that
one
class
might
turn
into a lot of machine code.
The
advantages
are
that
you
can
use
primitive
types, and you get code optimized
for
each
type.
(Java
generics
don’t
work
with primitive types.)
"for
each"
on
Arrays
====================Java
has
a
"for
each"
loop for iterating through the elements of an array.
int[]
array
for
(int
i
array)
System.out.print(i
Note
that
i
is
not
iterating from 0 to 5; it’s taking on the value of each
array
element
in
turn.
You can iterate over arrays of any type this way.
String
concat
for
(String
s
stringArray) {
concat
concat
s;
For
some
reason,
the
type declaration must be in the "for" statement.
The
compiler
barfs
if
you
try
int
i;
for
(i
array)
===============Just
as
methods
can
be
overridden in subclasses, fields can be "shadowed" in
subclasses.
However,
shadowing works quite differently from overriding.
Whereas
the
choice
of
methods is dictated by the dyanamic_type of an object,
the
choice
of
fields
is
dictated by the static_type of a variable or object.
class
Super
int
x
int
f()
return
} class
Sub
extends
Super {
int
x
// shadows Super.x
int
f()
return
// overrides Super.f()
Any
object
of
class
Sub
now has two fields called x, each of which store a
different
integer.
How
do we know which field is accessed when we refer to x?
It
depends
on
the
static type of the expression whose x field is accessed.
Sub
sub
new
Sub();
Super
supe
sub;
// supe and sub reference the same object.
int
i;
sub
|Sub.x Super.x |
supe
i
supe.x;
i
sub.x;
i
((Super)
sub).x;
i
((Sub)
supe).x;
The
last
four
statements all use the same object, but yield different results.
Recall
that
method
overriding does not work the same way.
Since both variables
reference
a
Sub,
the
method Sub.f always overrides Super.f.
i = supe.f();
i = sub.f();
i = ((Super) sub).f();
i = ((Sub) supe).f();
What if the variable whose
shadowed
field
you
want
to
access
is
"this"?
You can cast "this" too, but
a
simpler
alternative
is
to
replace
"this"
with
"super".
class Sub extends Super {
int x = 4;
shadows
Super.x
void g() {
int i;i = this.x;
i = ((Super) this).x
i = super.x;
Whereas method overriding is
a
powerful
benefit
of
object
orientation,
field
shadowing is largely a nuisance.
Whenever
possible,
avoid
having
fields
in
subclasses whose names are
the
same
as
fields
in
their
superclasses.
Static methods can be shadowed
too;
they
follow
the
same
shadowing
rules
as
fields.
This might seem confusing:
why
do
ordinary,
non-static
methods
use
one system (overriding) while
static
methods
use
an
entirely
different
system
(shadowing)?
The reason is
because
overriding
requires
dynamic
method
lookup.
A static method is not called
on
an
object,
so
there’s
nothing
whose
dynamic
type we can look up.
Therefore,
static
methods
can’t
use
dynamic
method
lookup or overriding.
So they
use
shadowing
instead.
Static method shadowing, like
field
shadowing,
is
largely
a
nuisance.
"final" METHODS AND CLASSES===========================A method can be declared "final"
to
prevent
subclasses
from
overriding
it.
Any
attempt to override it will
cause
a
compile-time
error.
A class can be declared "final"
to
prevent
it
from
being
extended.
Any
attempt
to declare a subclass will
cause
a
compile-time
error.
The only reason to declare
a
method
or
class
"final"
is
to
improve
the
speed
of
a program.
The compiler can
speed
up
method
calls
that
cannot
be
overridden.