Thumbs up for suppressable exceptions in JDK 1.7

J

Jan Burse

Dear All

Was just playing around with suppressable exceptions
in JDK 1.7. This looks like a great improvement for
bug hunting!

Best Regards

Manually Suppressed:
------------------

public class TestSuppressed {

public static void main(String[] args) throws Exception {
try {
throw new IllegalArgumentException("x");
} catch (IllegalArgumentException x) {
x.addSuppressed(new IllegalArgumentException("y"));
throw x;
}
}

}

gives:

Exception in thread "main" java.lang.IllegalArgumentException: x
at TestSuppressed.main(TestSuppressed.java:12)
Suppressed: java.lang.IllegalArgumentException: y
at TestSuppressed.main(TestSuppressed.java:14)
... 5 more

Automatically Suppressed:
---------------------

public class TestSuppressed implements AutoCloseable {

public static void main(String[] args) throws Exception {
try (TestSuppressed ts=new TestSuppressed()) {
throw new IllegalArgumentException("x");
}
}

public void close() throws Exception {
throw new IllegalArgumentException("y");
}

}

gives:

Exception in thread "main" java.lang.IllegalArgumentException: x
at TestSuppressed.main(TestSuppressed.java:9)
Suppressed: java.lang.IllegalArgumentException: y
at TestSuppressed.close(TestSuppressed.java:20)
at TestSuppressed.main(TestSuppressed.java:10)
... 5 more
 
R

Roedy Green

Dear All

Was just playing around with suppressable exceptions
in JDK 1.7. This looks like a great improvement for
bug hunting!

Best Regards

Manually Suppressed:
------------------

public class TestSuppressed {

public static void main(String[] args) throws Exception {
try {
throw new IllegalArgumentException("x");
} catch (IllegalArgumentException x) {
x.addSuppressed(new IllegalArgumentException("y"));
throw x;
}
}

}

gives:

Exception in thread "main" java.lang.IllegalArgumentException: x
at TestSuppressed.main(TestSuppressed.java:12)
Suppressed: java.lang.IllegalArgumentException: y
at TestSuppressed.main(TestSuppressed.java:14)
... 5 more

Automatically Suppressed:
---------------------

public class TestSuppressed implements AutoCloseable {

public static void main(String[] args) throws Exception {
try (TestSuppressed ts=new TestSuppressed()) {
throw new IllegalArgumentException("x");
}
}

public void close() throws Exception {
throw new IllegalArgumentException("y");
}

}

gives:

Exception in thread "main" java.lang.IllegalArgumentException: x
at TestSuppressed.main(TestSuppressed.java:9)
Suppressed: java.lang.IllegalArgumentException: y
at TestSuppressed.close(TestSuppressed.java:20)
at TestSuppressed.main(TestSuppressed.java:10)
... 5 more

I think you need some exposition on why this is a good thing.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
J

Jan Burse

Roedy said:
I think you need some exposition on why this is a good thing.

Its a good think for hunting down bugs. You don't
have to sift through some logs written in the finally
clause of some try/catch, you can even spare this code.

But instead you get all layed out in front of you in
the exceptions catched in the toplevel of your application.
Or eventually written from there to some log.

Agreed?

Best Regards
 
T

Tom Anderson

I think you need some exposition on why this is a good thing.

It avoids this common mistake:

try {
doSomethingWhichMightThrowAnException();
}
finally {
doSomeCleanupWhichMightThrowAnException();
}

In that code, if both methods throw an exception, you will only see the
second. The first exception - the one which actually caused the problem -
will be lost. It's as if the VM has a very short attention span, and can
only focus on whatever exception was most recently thrown.

In Java 7, you can put the cleanup into the close() method of an
(Auto)Closeable, and use the try-with-resources form:

class Thing implements AutoCloseable {
public void close() throws AnException {
doSomeCleanupWhichMightThrowAnException();
}
}

try (Thing t = new Thing()) {
doSomethingWhichMightThrowAnException();
}

There, the compiler will arrange things so that if close() does throw an
exception, it will be 'suppressed', and tagged on to the exception coming
from doSomethingWhichMightThrowAnException() as a suppressed exception.

tom
 
D

Daniele Futtorovic

It avoids this common mistake:

try {
doSomethingWhichMightThrowAnException();
}
finally {
doSomeCleanupWhichMightThrowAnException();
}

In that code, if both methods throw an exception, you will only see the
second. The first exception - the one which actually caused the problem
- will be lost. It's as if the VM has a very short attention span, and
can only focus on whatever exception was most recently thrown.

In Java 7, you can put the cleanup into the close() method of an
(Auto)Closeable, and use the try-with-resources form:

class Thing implements AutoCloseable {
public void close() throws AnException {
doSomeCleanupWhichMightThrowAnException();
}
}

try (Thing t = new Thing()) {
doSomethingWhichMightThrowAnException();
}

There, the compiler will arrange things so that if close() does throw an
exception, it will be 'suppressed', and tagged on to the exception
coming from doSomethingWhichMightThrowAnException() as a suppressed
exception.

tom

Indeed, but even more generally, we can from now on register
"suppressed" exceptions ourselves, as Jan's code and the JSE7 Javadoc
for java.lang.Throwable show. Great Thing IMHO. Closes a hole that's
been lurking there for a very long time.

Thanks Jan for bringing this to my attention.
 
D

Daniel Pitts

Indeed, but even more generally, we can from now on register
"suppressed" exceptions ourselves, as Jan's code and the JSE7 Javadoc
for java.lang.Throwable show. Great Thing IMHO. Closes a hole that's
been lurking there for a very long time.

Thanks Jan for bringing this to my attention.

This will definitely be a big help debugging issues. It may also help
fill up log files faster ;-). I can see it being extremely useful in a
try/catch/retry scenario (such as a service which tries a few times to
connect to a remote machine, and gets a different error each time).

I want to read up on it, but I wonder if it will help with this
(unfortunate) situation:

try {
buggyCodeThrowsNullPointerException();
} catch (Exception oopsThisWasIgnoredByLazyProgrammer) {
throw new BusinessLayerSpecificException(
"Unable to process request for no good reason.");
}

This suppresses a bug, but the original programmer wasn't thinking about
potential bugs, only recoverable exceptions. The exception is
effectively suppressed.
 
D

Daniele Futtorovic

I want to read up on it, but I wonder if it will help with this
(unfortunate) situation:

try {
buggyCodeThrowsNullPointerException();
} catch (Exception oopsThisWasIgnoredByLazyProgrammer) {
throw new BusinessLayerSpecificException(
"Unable to process request for no good reason.");
}

This suppresses a bug, but the original programmer wasn't thinking about
potential bugs, only recoverable exceptions. The exception is
effectively suppressed.

Probably won't help that situation.

The suppressed exception mechanism addresses a structural short-coming
of the Java core libraries. If at any point you were confronted with two
Throwables (and their respective stack of causes), and planned to throw
something, you had no choice but to decide to drop one of the two.

The situation you're describing here is not a structural problem, it's
bad code. Language changes can sometimes facilitate good code or the
opposite, but they're not a solution to bad code. The only guaranteed
safeguard against bad coding is not coding at all.

In other words, while the structural problem could be addressed by a
change in the language/libraries, I don't think the one of bad code can.
 
A

Arved Sandstrom

On 11-09-29 01:05 PM, Daniele Futtorovic wrote:
[ Useful info snipped ]
Indeed, but even more generally, we can from now on register
"suppressed" exceptions ourselves, as Jan's code and the JSE7 Javadoc
for java.lang.Throwable show. Great Thing IMHO. Closes a hole that's
been lurking there for a very long time.

Thanks Jan for bringing this to my attention.
Indeed, I second that sentiment. I had missed this interesting bit of
information.

AHS
 
J

Jan Burse

Daniel said:
I want to read up on it, but I wonder if it will help with this
(unfortunate) situation:

try {
buggyCodeThrowsNullPointerException();
} catch (Exception oopsThisWasIgnoredByLazyProgrammer) {
throw new BusinessLayerSpecificException(
"Unable to process request for no good reason.");
}

I would eventually do the following:

try {
buggyCodeThrowsNullPointerException();
} catch (Exception oopsThisWasIgnoredByLazyProgrammer) {
throw new BusinessLayerSpecificException(
"Unable to process request for no good reason.",
oopsThisWasIgnoredByLazyProgrammer);
}

So use the cause of an exception for piggybacking
the reason. This is a kind of a competing mechanism
to supression.

Bye
 
J

Jan Burse

Jan said:
Dear All

Was just playing around with suppressable exceptions
in JDK 1.7. This looks like a great improvement for
bug hunting!

Best Regards

Just see that java.sql.Statement implements AutoClosable
in JDK 1.7. Is this also worth a thumbs up?

Unfortunately not yet. If I am using some java database
object cursors, then I typically have some database
beans as follows:

class Bean() {
void open();
boolean next();
void close();
}

Then I have to wait until my DBBean also implements
the AutoClosable interface. As I cannot use the
try-with-resource statement. Since the SQL statement
is burried in the Bean.

Any other interesting classes that have received the
AutoCloseable interface in JDK 1.7? My IDE says that
around ~580 classes/interfaces implemented/extend
this interface!

Bye
 
J

Jan Burse

Jan said:
Any other interesting classes that have received the
AutoCloseable interface in JDK 1.7? My IDE says that
around ~580 classes/interfaces implemented/extend
this interface!

Ok the number is so high, because in JDK 1.7 Closeable
extendes AutoCloseable. But we find classes such as

javax.sound.midi.Receiver
javax.sound.midi.MidiDevice
javax.sound.midi.Transmitter
javax.sound.sampled.Line
javax.sql.ResultSet
javax.sql.Connection

Which are genuine AutoClosable.

Bye
 
T

Tom Anderson

Ok the number is so high, because in JDK 1.7 Closeable
extendes AutoCloseable. But we find classes such as

javax.sound.midi.Receiver
javax.sound.midi.MidiDevice
javax.sound.midi.Transmitter
javax.sound.sampled.Line
javax.sql.ResultSet
javax.sql.Connection

Which are genuine AutoClosable.

I believe that they automatically added AutoCloseable to every class or
interface with a no-args close() method. That's quite a few.

tom
 

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,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top