Java Reference
In-Depth Information
main
should catch it, so it seems a safe bet that the program will print
I told you so
. But if you
tried running it, you found that it does nothing of the sort: It throws a
StackOverflowError
. Why?
Like most programs that throw a
StackOverflowError
, this one contains an infinite recursion.
When you invoke a constructor, the
instance variable initializers run before the body of the
constructor
[JLS 12.5]. In this case, the initializer for the variable
internalInstance
invokes the
constructor recursively. That constructor, in turn, initializes its own
internalInstance
field by
invoking the
Reluctant
constructor again and so on, ad infinitum. These recursive invocations
cause a
StackOverflowError
before the constructor body ever gets a chance to execute. Because
StackOverflowError
is a subtype of
Error
rather than
Exception
, the
catch
clause in
main
doesn't
catch it.
It is not uncommon for an object to contain instances of its own type. This happens, for example, in
linked list nodes, tree nodes, and graph nodes. You must initialize such contained instances
carefully to avoid a
StackOverflowError
.
As for the nominal topic of this puzzle— constructors declared to throw exceptions— note that
a
constructor must declare any checked exceptions thrown by its instance initializers.
This
program, which illustrates a common service-provider pattern, won't compile, because it violates
this rule:
public class Car {
private static Class engineClass = ... ; // Service provider
private Engine engine = (Engine) engineClass.newInstance();
public Car() { }
// Throws two checked exceptions!
}
Although it has no body, the constructor throws two checked exceptions:
InstantiationException
and
IllegalAccessException
. They are thrown by
Class.newInstance
, which is called when
initializing the
engine
field. The best way to fix this is to create a private static helper method that
computes the initial value of the field and handles exceptions appropriately. In this case, let's
assume that the
Class
object referred to by
engineClass
was chosen to guarantee that it is both
accessible and instantiable. The following version of
Car
compiles without error:
// Fixed - instance initializers don't throw checked exceptions
public class Car {
private static Class engineClass = ... ;
private Engine engine = newEngine();
Search WWH ::
Custom Search