Throwing Constructor Exceptions and cleaning up

R

Roedy Green

For example, if I open a file, or connect a socket while constructing an
object and then throw an exception before the constructor/instantiation
completes, then what happens to the file or socket connections that were
successfully instantiated?

there is a three stage process:

1. allocating some space for the object.

2. zeroing it.

3. running the constructor to initialise the fields

4. returning a handle to the object to your app.

The object does not exist until step (4) happens so that space is
no-mans land. It won't get reused until the next GC however.

I believe the constructor might have called methods that passed this,
so the object may exist in a half-completed stated with references
retained by those methods.

From Java's point of view, once the fields are zeroed, they can no
longer crash the JVM, so whether the object was properly initialised
is nothing for the JVM to fret over. There are lots of goofy things
you can do in initialisation code that will end up with corrupt
objects.



--
Roedy Green Canadian Mind Products
http://mindprod.com

"Think of the earth as a living organism that is being attacked by billions of bacteria whose numbers double every forty years. Either the host dies, or the virus dies, or both die."
~ Gore Vidal
 
E

Eric Sosman

Arne said:
[...]
How often will code use unmanaged resource that needs cleanup
and having some finalizer code run and figure out that it does
not need to do anything have a noticeable performance impact?

Most managed resources are pretty expensive to "open" and
"close" and an extra method call that test if something is
null (or similar) should mean nothing.

Just anecdotal, but in "Effective Java" Bloch tells of a
case where finalize() provoked OutOfMemoryError. It seems
that the program was creating graphics objects and turning
them to garbage, on a thread that ran at higher priority
than the finalization thread. Result: The to-be-finalized
queue grew until no heap space remained.
 
L

Lew

Peter said:
Regardless, whatever you think is "typical" or not, Java and .NET are
not so different, and the Microsoft developers are not so stupid, that
your statements of "typical" offer any sort of compelling
counter-argument to the possibility that a finalizer optimization might
be useful. It's much more likely that you've simply overlooked some
significant use case.

Just as one might conclude that .NET's inclusion of the feature evidences that
it's possible, one might conclude that Java's exclusion of it evidences that
Java's designers, who are also "not so stupid", deemed it insufficiently useful.
 
K

Karl Uppiano

Richard Maher said:
Hi,

If when an object's constructor throws an exception that object has not in
fact been intantiated, then what happens to the bits/objects/variables
that
were initialized/instantiated before the exception was thrown?

For example, if I open a file, or connect a socket while constructing an
object and then throw an exception before the constructor/instantiation
completes, then what happens to the file or socket connections that were
successfully instantiated?

a) Garbage Collected in the fullness of time as they're no longer
referenced?
b) Destroyed, and o/ride finalize() method that's called immediately?
c) It's considered extremely bad form to do this in a constructor. Have an
init() method instead?

Who considers it bad form for a constructor to throw an exception? I can
think of at least two reasons why a constructor might throw an exception:
1. Bad parameters
2. Inability to allocate a necessary resource (memory, database, socket,
file, etc.)

I think it is better that the constructor throw an exception, letting you
know immediately that instance creation failed, vs. creating a zombie
instance, requiring that you explicitly check it for validity, and all the
merry mixups that occur when you forget. An exception is harder to forget,
and more explicit, IMHO.
d) Make sure you close the file/Socket before throwing the exception

Absolutely. In some cases, the APIs that the constructor needs to call will
themselves throw exceptions. The constructor needs to catch, cleanup any
resources acquired earlier. If you decide to throw a new exception or
otherwise allow one to fly from inside the constructor, you first need to
undo what you have done so far. A well-placed "finally" block can be very
effective in cases where you just want to "let fly" with an exception thrown
by some API that you're using.
 
L

Lew

Peter said:
Keeping in mind, however, that the .NET designers had the benefit of
hindsight, being able to look at what Java did and make more informed
decisions about what's useful, what's not, what works, and what doesn't.

There are a number of things that .NET, and its flagship language C#,
offer that are not in Java, and which are patently useful. Their lack
of presence in Java says more to me about the trailblazing nature of the
Java creators (and in particular, the sheer impossibility of
anticipating every possible useful feature), than it does about whether
those feature's would actually be useful in Java or not.

But yes...the fact is, it's _possible_ that such an optimization isn't
useful at all, and is just a waste of time and code in .NET. My point
is that it's premature for any of us to make a claim one way or the
other. It's just as likely that it's in fact doing something useful in
.NET, as it is that it's not.

Good points.
 
L

Lew

Richard Maher wrote ...
You would basically do this specifically to adhere to the "resource
acquisition is initialization" (RAII) idiom.
<http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization>

I prefer personally to think of this as "destruction is resource release", but
the point is to tie the resource to the lifetime of the object itself.

However, one does not always follow this pattern; sometimes one prefers to
construct the object first, and acquire or release resources only from
fully-constructed objects.

Karl said:
Absolutely. In some cases, the APIs that the constructor needs to call
will themselves throw exceptions. The constructor needs to catch,
cleanup any resources acquired earlier. If you decide to throw a new
exception or otherwise allow one to fly from inside the constructor, you
first need to undo what you have done so far. A well-placed "finally"
block can be very effective in cases where you just want to "let fly"
with an exception thrown by some API that you're using.

The key is that the 'finally' be well placed.

This consideration does sometimes lead to putting resource management in
methods on fully-constructed objects, especially given the lack of explicit
destructors in Java. It depends on the resource, too. A socket may be better
handled in a constructor (perhaps with a last-ditch cleanup in 'finalize' as
discussed elsewhere in this thread). A GUI should not be started in the
constructor, although it should be constructed in the constructor.

The choices hinge on how one ties lifetimes together - the lifetime of the
object and the lifetime of the resource.
 
R

Richard Maher

Hi all,

Arved Sandstrom said:
Arne said:
Lew wrote:
[ SNIP ]
There are some cases where an exception in the constructor seems
natural.

IO classes and FileNotFoundException is one example.

Arne

The latter seems natural only because that's how the Sun programmers set
the classes up. To me what would seem natural is to call an open()
method on a File instance and either have a File[Input|Output]Stream
returned, or have a FileNotFoundException thrown at that point (if you
want to go with an exception).

What java.io.File should really be called is java.io.FileName, or
something similar. If there was then still a java.io.File class, some
of the methods (like the ones that check permissions) would logically
stay there, and one would add methods like open() and close(). The
FileInputStream or FileOutputStream would simply be used for reads and
writes.

Just my opinion.

AHS

Thanks everyone for a very interesting and instructive thread!

I replied to this post only 'cos the classes in the part of my design that
are particulary effected by these clean-up issues are quite opposite to what
Arved has suggested here. But in the light of all that's been discussed here
I'm still comfortable with how it's panning out, so I'm gonna pursue it a
bit further for the moment.

For me, the important bits were: - finalize() is really just belt-and-braces
and not a destructor, everything is GC'ed at process exit, and you gotta
clean-up after yourself, there's no magic-wand or guaranteed
rundown-handler. As the man who refused a lift from an Australian farmer was
heard to say "Shut your own bloody gates!" :)

Cheers Richard Maher
 
A

Arne Vajhøj

Richard said:
For me, the important bits were: - finalize() is really just belt-and-braces
and not a destructor, everything is GC'ed at process exit,

Note that finalizers will not necessarily be run at JVM exit.

It will only be guaranteed if System runFinalizersOnExit is called.

And that method is deprecated in every sense of the word.
> and you gotta
clean-up after yourself, there's no magic-wand or guaranteed
rundown-handler.

Yep.

Try catch finally and do the right thing.

Arne
 
A

Arne Vajhøj

Eric said:
Arne said:
[...]
How often will code use unmanaged resource that needs cleanup
and having some finalizer code run and figure out that it does
not need to do anything have a noticeable performance impact?

Most managed resources are pretty expensive to "open" and
"close" and an extra method call that test if something is
null (or similar) should mean nothing.

Just anecdotal, but in "Effective Java" Bloch tells of a
case where finalize() provoked OutOfMemoryError. It seems
that the program was creating graphics objects and turning
them to garbage, on a thread that ran at higher priority
than the finalization thread. Result: The to-be-finalized
queue grew until no heap space remained.

Finalizers should be avoided. Period.

Arne
 
A

Arne Vajhøj

Peter said:
Typical managed resources relate to IO. [...]

I assume you mean "unmanaged resources".

Yep. Sorry.
In any case...

That's highly dependent on your target application. It may be true for
a server-side component -- though, even there you also have lots of
other kinds of unmanaged resources, such as synchronization objects,
threads, etc. -- but for a client-side GUI application, most of the
unmanaged resources are likely to be related to the GUI itself (for
heavyweight OS-based components, that is).

Well - most of the GUI stuff will be IO - I don't think there will
be much left of unmanaged resources if everything related to
screen output and keyboard & mouse input were removed.
Regardless, whatever you think is "typical" or not, Java and .NET are
not so different, and the Microsoft developers are not so stupid, that
your statements of "typical" offer any sort of compelling
counter-argument to the possibility that a finalizer optimization might
be useful. It's much more likely that you've simply overlooked some
significant use case.

I think that depends on how you think.

If X says and I heard from Y and I read in Z is seen as indication
of something then yes.

If one believe in logic and understanding of the causalities then no.

Very good arguments have been presented for why it should not matter.

No one has been able to come up with any hints about where it could
really make a significant difference.

The available facts say that it does not matter.

I think that is the relevant stuff.

Speculation about that the .NET designer really spend time considering
this and that the arguments also applies to Java is just
that - speculation.

Arne
 
A

Arne Vajhøj

Arved said:
Arne said:
Lew wrote:
[ SNIP ]
There are some cases where an exception in the constructor seems
natural.

IO classes and FileNotFoundException is one example.

The latter seems natural only because that's how the Sun programmers set
the classes up. To me what would seem natural is to call an open()
method on a File instance and either have a File[Input|Output]Stream
returned, or have a FileNotFoundException thrown at that point (if you
want to go with an exception).

True.

But having IO classes with a constructor that opens is a rather
common way of doing things - Java is far from the only language
doing that.
What java.io.File should really be called is java.io.FileName, or
something similar.

I completely agree with that !

Arne
 
A

Arne Vajhøj

Peter said:
That's exactly my point.

Keeping in mind, however, that the .NET designers had the benefit of
hindsight, being able to look at what Java did and make more informed
decisions about what's useful, what's not, what works, and what doesn't.

There are a number of things that .NET, and its flagship language C#,
offer that are not in Java, and which are patently useful. Their lack
of presence in Java says more to me about the trailblazing nature of the
Java creators (and in particular, the sheer impossibility of
anticipating every possible useful feature), than it does about whether
those feature's would actually be useful in Java or not.

But yes...the fact is, it's _possible_ that such an optimization isn't
useful at all, and is just a waste of time and code in .NET. My point
is that it's premature for any of us to make a claim one way or the
other. It's just as likely that it's in fact doing something useful in
.NET, as it is that it's not.

If you count implementations as an indication for usefulness then it
is 50%-50%.

But I consider it a lot or more useful to analyze the technical
substance.

Based on this thread it seems as if it is 99%-1%.

Arne
 
A

Arne Vajhøj

Karl said:
Who considers it bad form for a constructor to throw an exception? I can
think of at least two reasons why a constructor might throw an exception:
1. Bad parameters
2. Inability to allocate a necessary resource (memory, database, socket,
file, etc.)

I think it is better that the constructor throw an exception, letting
you know immediately that instance creation failed, vs. creating a
zombie instance, requiring that you explicitly check it for validity,
and all the merry mixups that occur when you forget. An exception is
harder to forget, and more explicit, IMHO.

I think that as states by someone previously the problem is more
with constructors that does so much that throwing an Exception
is necessary than throwing the exception. As you explain it, then
if it need to then it need to.

Arne
 
R

Richard Maher

Hi Lew,

Lew said:
Richard Maher wrote ... an

You would basically do this specifically to adhere to the "resource
acquisition is initialization" (RAII) idiom.
<http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization>

Certainly looks similar.
I prefer personally to think of this as "destruction is resource release", but
the point is to tie the resource to the lifetime of the object itself.

However, one does not always follow this pattern; sometimes one prefers to
construct the object first, and acquire or release resources only from
fully-constructed objects.




The key is that the 'finally' be well placed.

This consideration does sometimes lead to putting resource management in
methods on fully-constructed objects, especially given the lack of explicit
destructors in Java. It depends on the resource, too. A socket may be better
handled in a constructor (perhaps with a last-ditch cleanup in 'finalize' as
discussed elsewhere in this thread). A GUI should not be started in the
constructor, although it should be constructed in the constructor.

Why not? Hey I don't like the idea at all either (especially if (or rather
when in my case :) the indefinite user interaction is inside a
synchronized block) Sounds bizarre I know but this is what's on the
whiteboard at the moment: -

An Applet instance will ask for a Session class from the static
SessionRegistry. If a Session object already exists for that combination of
ApplicationName/Host/Port etc then that is the one that will be chosen,
otherwise a new Session will be manufactured. Now Connection is an
inner-class of Session. The Connection constructor just creates a Socket and
works out if it's SSL or not. There are also open() and close() methods for
Connection that are invoked from the Session constructor. Furthermore after
a connection to a remote host has been made a Connection.handshake() must
take place with a username/password. If authorization fails then the
(network) connection must be torn down. (There with also be a Reader() inner
class with a thread that will read the Socket and hopefully dispatch the
messages to the corrct JSObject)

Anyway the relevant bit to your post is that somewhere in there a user will
have to be quized for a Username/Password. The Applet that's trying to
instantiate Session doesn't really care if another Applet instance has
already succesfully authorized client access on that Socket, or that a
Session instance may exist but the Connection and Reader classess have been
torn down 'cos there were no longer any pages referencing the Applet; it
just wants to say "gimme a Session for Application X, at my codebase() and
port number 1234, so that I can do some network i/o for my fat 'n' sexy RIA
client".

Now you might say that the Applet itself should do the synchronization and
be responsible for checking if authorization is needed via an isAuthorized()
and/or isConnected() mechanism, but the whole point is that the Socket be
connected/authorized only once per all pages/tabs (and where possible
browser instances). If that prevents firing up any additional pages for a
given application until they've entered the Username/Passsword for the first
page they brought up, then I'm good with it.

So is there a physical Java barrier(s) preventing the use of GUIs
EventListeners et al (at least a couple of modal dialogue boxes) from a
constructor or is it just considered "bad form"?
The choices hinge on how one ties lifetimes together - the lifetime of the
object and the lifetime of the resource.

Fair enough.

Regards Richard Maher
 
L

Larry K. Wollensham

Arne said:
Note that finalizers will not necessarily be run at JVM exit.

It will only be guaranteed if System runFinalizersOnExit is called.

And that method is deprecated in every sense of the word.


Yep.

Try catch finally and do the right thing.

Remember that finally executes on any exit from the try block, including
success (fall out or return from inside it, or break or continue from
inside it to outside it).

Something like this will work:

public class MyClass {
private final InputStream wrapped;

public MyClass (int arg1) throws IOException {
if (arg1 < 0) throw new IllegalArgumentException();
boolean success = false;
InputStream w = null;
try {
w = new FileInputStream(getFile(arg1));
someSetupStuffThatMayThrow();
wrapped = w;
success = true;
} finally {
if (w != null && !success) w.close();
}
}

private static File getFile (int arg1) { ... }
private static void someSetupStuffThatMayThrow ()
throws IOException { ... }
}

The finally block cleans up by closing the InputStream only if a success
flag wasn't put up at the end of the try body (and only if the stream
itself was opened successfully).

If the input stream can b0rk and the object (or at least the stream) is
useless once this has occurred, every method that uses the stream may
wish to catch IOException, close the stream, and rethrow. The object
might wish to make all future operations (at least involving the stream)
fail fast with a non-checked exception after this; simply setting the
stream to null works (if it's not final; it is in the example above).

The constructor however has to deal with the possibility of any
exception at all, not just ones that invalidate the stream, because
unhandlable ones will invalidate the whole object. This includes OOME or
other Errors. Hence the need for a finally block that cleans up under
every circumstance other than a clear success. Maximum safety occurs if
putting the success flag up is the last thing done before the try body
exits, and nothing is done after the try body (and the finally body)
except to fall out of the constructor.
 
L

Lew

Larry said:
Remember that finally executes on any exit from the try block, including
success (fall out or return from inside it, or break or continue from
inside it to outside it).

Something like this will work:

public class MyClass {
private final InputStream wrapped;

public MyClass (int arg1) throws IOException {
if (arg1 < 0) throw new IllegalArgumentException();
boolean success = false;
InputStream w = null;
try {
w = new FileInputStream(getFile(arg1));
someSetupStuffThatMayThrow();
wrapped = w;
success = true;
} finally {
if (w != null && !success) w.close();
}
}

private static File getFile (int arg1) { ... }
private static void someSetupStuffThatMayThrow ()
throws IOException { ... }
}

The finally block cleans up by closing the InputStream only if a success
flag wasn't put up at the end of the try body (and only if the stream
itself was opened successfully).

Another approach puts separate try blocks around things that can fail.

public MyClass (int arg1) throws IOException
{
if (arg1 < 0) throw new IllegalArgumentException();
InputStream w = new FileInputStream(getFile(arg1));
assert w != null;
try
{
someSetupStuffThatMayThrow();
}
finally
{
w.close();
}
}
 
L

Larry K. Wollensham

Lew said:
Another approach puts separate try blocks around things that can fail.

public MyClass (int arg1) throws IOException
{
if (arg1 < 0) throw new IllegalArgumentException();
InputStream w = new FileInputStream(getFile(arg1));
assert w != null;
try
{
someSetupStuffThatMayThrow();
}
finally
{
w.close();
}
}

That'll close w no matter what, and doesn't assign it to an instance
variable. If the stream is simply consulted during construction, but
isn't retained open as a part of the object, this makes sense. If it is,
you need the success flag or something similar again so the finally
clause only closes it conditionally, and you need to assign it to
something visible to the rest of the class.
 
L

Lew

That'll close w no matter what, and doesn't assign it to an instance
variable. If the stream is simply consulted during construction, but
isn't retained open as a part of the object, this makes sense. If it is,
you need the success flag or something similar again so the finally
clause only closes it conditionally, and you need to assign it to
something visible to the rest of the class.

You're right. I should not have gotten rid of the 'success' flag.

What I should have said:

public MyClass (int arg1) throws IOException
{
if (arg1 < 0) throw new IllegalArgumentException();
wrapped = new FileInputStream(getFile(arg1));
assert wrapped != null;
boolean success = false;
try
{
someSetupStuffThatMayThrow();
success = true;
}
finally
{
if ( ! success )
{
wrapped.close();
}
}
}

To get rid of the 'success' variable, have a catch block catch the
exceptions from 'someSetupStuffThatMayThrow()' and close the stream.

public MyClass (int arg1) throws IOException
{
if (arg1 < 0) throw new IllegalArgumentException();
wrapped = new FileInputStream(getFile(arg1));
assert wrapped != null;
try
{
someSetupStuffThatMayThrow();
}
catch ( SetupException exc )
{
final String msg = "setup failed";
logger.error( msg );
try
{
wrapped.close();
}
catch ( IOException ioex )
{
logger.error( "wrapped.close() failed" );
}
throw new IllegalStateException( msg, exc );
}
}
 
L

Larry K. Wollensham

Lew said:
You're right. I should not have gotten rid of the 'success' flag.

What I should have said:

[snip code]
To get rid of the 'success' variable, have a catch block catch the
exceptions from 'someSetupStuffThatMayThrow()' and close the stream.
[snip]

try
{
someSetupStuffThatMayThrow();
}
catch ( SetupException exc )

[snip]

This has the problem of leaking file handles if an unexpected exception
occurs (a RuntimeException or Error). Depending on whether the caller
may recover from these, or invariably screams and dies right away, it
may not matter. (If they always cause an immediate exit, the OS will
close the file handle almost as quickly.)

My preference is to not depend on certain usage patterns by the caller.
The caller might catch and recover from, say, OOME somehow, so I would
prefer to always close the stream if the constructor doesn't succeed and
exit normally.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top