I am trying to understand suppressed Exceptions in Java SE7, I posted 2 examples below, They are similar, In the following example, I was under the impression that when new "main Exception" happens, the suppressed ones get ignored, for instance I was expecting the output to be "java.lang.RuntimeException: y", However the answer is:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
Here is the code:
class Animal implements AutoCloseable{
#Override
public void close() {
throw new RuntimeException("a");
}
}
public class ExceptionsDemo {
public static void main(String[] args) throws IOException {
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
static void foo() {
try {
throw new RuntimeException("x");
} catch (Exception e) {
throw new RuntimeException("y");
}
}
}
My understanding was that after tryWithResources clause, "a" is main Exc, then in foo(), x becomes main exc while a gets suppressed, but in catch, I thought y will become the solo main exc and will ignore all other exceptions including suppressed ones? Like this second example, It does what I just mentioned, it outputs java.lang.RuntimeException: c with no suppressed exceptions.
public class ExceptionDemo2 {
class Animal implements AutoCloseable{
#Override
public void close() {
throw new RuntimeException("a");
}
}
public static void main(String[] args) {
try{
new ExceptionDemo2().go();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
void go(){
try(Animal a = new Animal()){
throw new IOException();
}catch(Exception e){
throw new RuntimeException("c");
}
}
}
output: java.lang.RuntimeException: c
Your example
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
terminates because foo() throws a RuntimeException (y). That's the target of the catch. Because execution leaves the try block, all declared resources are closed. While closing the Animal instance, another RuntimeException (a) is thrown. That one is suppressed because it wasn't the root cause.
The translation of try-with-resources to a try-catch-finally block is explained in the JLS, here.
The meaning of a basic try-with-resources statement:
try ({VariableModifier} R Identifier = Expression ...)
Block
is given by the following translation to a local variable declaration
and a try-catch-finally statement:
{
final {VariableModifierNoFinal} R Identifier = Expression;
Throwable #primaryExc = null;
try ResourceSpecification_tail
Block
catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (Identifier != null) {
if (#primaryExc != null) {
try {
Identifier.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
Identifier.close();
}
}
}
}
where
If the resource specification declares one resource, then
ResourceSpecification_tail is empty (and the try-catch-finally
statement is not itself a try-with-resources statement).
Your code above basically translates to something like
try {
final Animal a1 = new Animal();
Throwable thr = null;
try {
foo();
} catch (Throwable root) {
thr = root;
throw root;
} finally {
if (a1 != null) {
if (thr != null) {
try {
a1.close();
} catch (Throwable suppressed) {
thr.addSuppressed(suppressed); // <<<<<< suppressing the failure of 'close'
}
} else {
a1.close();
}
}
}
} catch (Exception e) {
System.err.println(e);
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
}
This is confusing because it mixes try-with-resources with the exception-masking behavior that try-with-resources is supposed to cure.
Also it seems like you're not aware of what it means for an exception to be suppressed. Suppressed means that the exception is tacked on to an existing exception, rather than being thrown, and in the progress causing the exception thrown within the try-block getting lost (the usual term is "masked").
Exception-masking means that an exception thrown from the finally or catch block results in any exception thrown from within the try block getting discarded. Since the exceptions thrown on in the try-blocks are usually descriptive of what your error is, and the exceptions thrown on close are usually uninteresting, this is a bad thing; try-with-resources was created in order to try to reduce the prevalence of this problem.
So in your first example, foo is called on a1 within the try block, within foo the exception thrown within the catch, y, masks the exception thrown in foo's try block. Then when the try-with-resources block is exited the close method is called and the exception thrown on close gets added onto the y exception that is in-flight. So your printlns show y, then iterate through the suppressed exceptions attached to y.
In the second example, c is what's thrown from the go method (it's the same masking behavior described above). The IOException in the go method try block got thrown, the close method was called on the way out, causing the exception on close to get added to the IOException as a suppressed exception, then the IOException gets masked by c. Because a got masked, and the suppressed exception was attached to a, we lose the suppressed exception too. The c exception thrown on close has no suppressed exceptions associated with it because it was generated after the try-with-resources block was exited.
From the Oracle documentation http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html:
If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.
So as expected the first example gives the output:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
In the second code snippet also there is a case of Exception Suppression. To validate that I have modified your function as:
void go() {
try (Animal a = new Animal()) {
throw new IOException();
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
throw new RuntimeException("c");
}
}
Then the output will be:
suppressed java.lang.RuntimeException: a
java.lang.RuntimeException: c
Related
Here's the code.
public class TestTest {
public static void main (String[] args) throws Exception {
try {
run();
} catch(Exception e) {
printSuppressedExceptions(e);
}
}
public static void printSuppressedExceptions(Throwable t) {
System.out.println(t);
System.out.println("suppressed exceptions: " + t.getSuppressed().length);
}
public static void run() throws Exception {
try(MyResource r = new MyResource("resource");) {
System.out.println("try");
System.getProperty("").length(); // throws illegalArgumentException
} catch(Exception e) {
printSuppressedExceptions(e);
throw e;
} finally {
new MyResource("finally").close();
}
}
}
class MyResource implements AutoCloseable {
private final String name;
public MyResource(String name) {
this.name = name;
}
#Override
public void close() throws Exception {
throw new Exception("exception" + " from " + this.name);
}
}
Since exception thrown from try block suppressed the exception from resource, I got "suppressed exceptions: 1" at first which was understandable. But when an exception was thrown from finally, it seemed like all suppressed exceptions disappeared because I got "java.lang.Exception: exception from finally" followed by "suppressed exceptions: 0" which I think it should be 1.
I browsed the Java tutorials and it definitely says
However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed.
From The try-with-resources Statement
How could it happen?
Here is code that does what you would expect:
public class TestTest {
public static void main (String[] args) throws Exception {
try {
run();
} catch(Exception e) {
printSuppressedExceptions(e);
}
}
public static void printSuppressedExceptions(Throwable t) {
System.out.println(t);
System.out.println("suppressed exceptions (" + t.getSuppressed().length + "):");
for (Throwable suppressed : t.getSuppressed()) {
System.out.println(" - " + suppressed);
}
}
public static void run() throws Exception {
Exception exceptionFromCatch = null;
try(MyResource r = new MyResource("resource");) {
System.out.println("try");
System.getProperty("").length(); // throws illegalArgumentException
} catch(Exception e) {
exceptionFromCatch = e;
printSuppressedExceptions(e);
throw e;
} finally {
try {
new MyResource("finally").close();
} catch (Exception e) {
if (exceptionFromCatch!=null) {
e.addSuppressed(exceptionFromCatch);
}
throw e;
}
}
}
}
class MyResource implements AutoCloseable {
private final String name;
public MyResource(String name) {
this.name = name;
}
#Override
public void close() throws Exception {
throw new Exception("exception" + " from " + this.name);
}
}
So lets go trough the try-with-resource part of your code (as introduced in JDK 1.7.0) and see what happens (see What is the Java 7 try-with-resources bytecode equivalent using try-catch-finally? for more details):
the try-with-resource block MyResource r = new MyResource("resource") is executed
the try block is executed and throws an IllegalArgumentException
the try-with-resource block calls close() for all resources (in your example only one)
close() throws an exception, but since the exception from the try block has priority the exception from thrown by close() is suppressed and added via addSuppressed(..)
So that part works like you expected from reading the tutorial.
And now the try-catch-finally part of your code (as in JDK 1.6 and earlier):
the try block is executed and throws an IllegalArgumentException
(the catch block behaves the same way as if there was no catch block)
the finally block is executed and throws an Exception
the exception from the finally block has priority and the one from the try block is suppressed
But this time the word suppressed used in the java tutorial does not stand for "suppressed and added to the actually thrown exception" but "suppressed and lost to nirvana". So it still behaves as in JDK 1.6 and earlier and does not make use of the newly introduced addSuppressed(..) getSuppressed() functionality. That's the reason it doesn't behave like you expected.
I would argue the behaviour you expected wouldn't be logical either. I would like it to behave like this:
...
} finally {
try {
new MyResource("finally").close();
} catch (Exception e) {
if (exceptionFromCatch!=null) {
exceptionFromCatch.addSuppressed(e);
} else {
throw e;
}
}
}
...
That would always give priority to the exception from the try block (as implemented with the new try-with-resource feature) and add the exception from the catch block as suppressed to the list. But that would break compatibility with JDK 1.6, so I guess that's the reason why it doesn't behave like that.
I have a Project with two classes. One Object class and one GUI class.
I would like to throw my own declared Exception if an error occurs.
I have two methods:
public class getValueClass {
private List<Value> liste;
public List<Value> getValues() {
try {
liste = this.getVal();
} catch (ValueException ex) {
System.out.println("EXCEPTION!! " + ex.getMessage());
ex.printStackTrace();
}
return liste;
}
public List<Value> getVal() throws ValueException
{
liste = null;
try {
// initialize list
// do some stuff
//test exception
if(1 == 1)
{
throw new Exception();
}
} catch (Exception ex) {
throw new ValueException("QWE " + ex);
}
return liste;
}
}
Now the exception is thrown and I catch the exception in my getValues Method and print the Message/Stack
But I call the Method getValues in my GUI-Class and I want to catch the Exception there and print some Information in my dialog!
GUI:
public void myMethod()
{
try
{
l = cs.getValues();
}
catch(Exception ex)
{
System.out.println("TEST " + ex.getMessage());
}
}
But I don't get there because I already catch it in the getValues() method.
Is it possible to make it like this WITHOUT adding throws at method declaration for getValues() method? ( I get this method from an interface and will not change it)
You could throw an unchecked RuntimeException such as IllegalArgumentException or customized RuntimeException subclass.
public List<Value> getValues() {
try {
liste = this.getVal();
} catch (ValueException ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
return liste;
}
There is a way to do what you want, but I advise against it depending on your intended purpose of ValueException, as it could be the source of future bugs
You can have ValueException extend RuntimeException. The RuntimeException set of exceptions, as the name implies, are thrown at runtime and are not declared at compile time, and need to be explicitly caught. This way you wouldn't have to add a throws declaration to the getValues() method, but would still catch it in your main method.
Disclaimer explained:
The reason I am not a fan of this idea (and RuntimeExceptions in general) is because they're uncaught until explicitly looked for. This in my mind doesn't make for easy-to-use code, and while it has it's very handy uses, I don't feel right using them because of the uncertainty they carry
Again, this is my opinion, not Java's
This is the code sample and I am getting an error "must be caught or declare to
be thrown" but I have
already handled the IOException. So can you please tell why the error is populating. The code also
follows the handle and declare rule.
public void rethrow() throws SQLException, IOException {
try {
couldThrowAnException();
}
catch(Exception e) {
e = new IOException();
throw e; //Error: must be caught or declare to be thrown
}
}
The problem you are running into is that the compiler deals with the variable declaration type, not the type you assign to the variable.
The variable is of type Exception, which is not part of the throws clause.
If you change the catch() clause to match IOException, it will compile.
I'd suggest you read the Exceptions Trail of the Java Language Tutorial.
You handled IOException but you are throwing Exception(not IOException ) from catch block.
So you have to add Exception in throws clause
or
catch IOException instead of Exception in the catch block
public void rethrow() throws SQLException, IOException {
try {
couldThrowAnException();
}
catch(IOException e) {
e = new IOException();
throw e; //Error: must be caught or declare to be thrown
}
}
Although, it makes no sens to cathc it and throw it...
A far better way would be:
public void rethrow() {
try {
couldThrowAnException();
}
catch(IOException e) {
//do something when you encounter the io-error
}
catch(SQLException e) {
//do something when you encounter the sql-error
}
}
import java.io.*;
class West1 extends Exception {
private String msg;
public West1() {
}
public West1(String msg) {
super(msg);
this.msg=msg;
}
public West1(Throwable cause) {
super(cause);
}
public West1(String msg,Throwable cause) {
super(msg,cause);
this.msg=msg;
}
public String toString() {
return msg;
}
public String getMessage() {
return msg;
}
}
public class West {
public static void main(String[] args) {
try {
throw new West1("Custom Exception.....");
}catch(West1 ce) {
System.out.println(ce.getMessage());
//throw new NumberFormatException();
throw new FileNotFoundException();
}catch(FileNotFoundException fne) {
fne.printStackTrace();
}/*catch(NumberFormatException nfe) {
nfe.printStackTrace();
}*/
}
}
In the above code, NumberFormatException is thrown from catch block it compile and run successfully but when FileNotFoundException is thrown from catch block it will not compile. Following Errors are thrown:
West.java:40: error: exception FileNotFoundException is never thrown in body of
corresponding try statement
}catch(FileNotFoundException fne){
West.java:39: error: unreported exception FileNotFoundException; must be caught
or declared to be thrown
throw new FileNotFoundException();
So my question is what is reason behind this behaviour?
NumberFormatException is a RuntimeException, meaning that it's not required to be declared in all methods it may be thrown. This means that, unlike FileNotFoundException, the compiler can not know if it can get thrown in a block or not.
The title implies you are trying to catch multiple exceptions at once, and your code implies you understand that you can have multiple catch blocks for a single try block to catch different types of exceptions. Everything is good so far, but you seem to misunderstand exactly where the try-catch catches errors.
Here is you code. I removed the comments to make it more concise.
public class West {
public static void main(String[] args) {
try {
throw new West1("Custom Exception.....");
} catch(West1 ce) {
System.out.println(ce.getMessage());
throw new FileNotFoundException(); // <-- Must be caught
} catch(FileNotFoundException fne) { // <-- Never thrown
fne.printStackTrace();
}
}
}
The first compiler error is because the catch block that is for catching FileNotFoundException's try block never throws FileNotFoundException. The second compiler error is because FileNotFoundException is a checked exception. Because it is a checked exception your code must either
handle it (by catching it with try-catch)
let everyone know it could throw it (public static void main(String[] args) throws FileNotFoundException { ...).
From the context of your code, you seem to be going with the first option, handling it with try-catch, but you have the catch in the wrong place.
catch blocks don't catch exceptions, try blocks do. catch blocks specify what to do with the actual caught exception.
public class West {
public static void main(String[] args) {
try {
throw new West1("Custom Exception.....");
} catch(West1 ce) {
System.out.println(ce.getMessage());
try {
throw new FileNotFoundException();
} catch(FileNotFoundException fne) {
fne.printStackTrace();
}
}
}
}
Try that instead. Notice how you can have a try instead of a catch. This wouldn't matter if FileNotFoundException wasn't a checked exception.
This question already has answers here:
Close resource quietly using try-with-resources
(4 answers)
Closed 1 year ago.
I was reading about the try-with-resource in JDK7 and while I was thinking of upgrading my application to run with JDK7 I faced this problem..
When using a BufferedReader for example the write throws IOException and the close throws IOException.. in the catch block I am concerned in the IOException thrown by the write.. but I wouldn't care much about the one thrown by the close..
Same problem with database connections.. and any other resource..
As an example I've created an auto closeable resource:
public class AutoCloseableExample implements AutoCloseable {
public AutoCloseableExample() throws IOException{
throw new IOException();
}
#Override
public void close() throws IOException {
throw new IOException("An Exception During Close");
}
}
Now when using it:
public class AutoCloseTest {
public static void main(String[] args) throws Exception {
try (AutoCloseableExample example = new AutoCloseableExample()) {
System.out.println(example);
throw new IOException("An Exception During Read");
} catch (Exception x) {
System.out.println(x.getMessage());
}
}
}
how can I distinguish between such exceptions without having to create wrappers for classes such as BufferedReader?
Most of cases I put the resource close in a try/catch inside the finally block without caring much about handling it.
Lets consider the class:
public class Resource implements AutoCloseable {
public Resource() throws Exception {
throw new Exception("Exception from constructor");
}
public void doSomething() throws Exception {
throw new Exception("Exception from method");
}
#Override
public void close() throws Exception {
throw new Exception("Exception from closeable");
}
}
and the try-with-resource block:
try(Resource r = new Resource()) {
r.doSomething();
} catch (Exception ex) {
ex.printStackTrace();
}
1. All 3 throw statements enabled.
Message "Exception from constructor" will printed and the exception thrown by constructor will be suppressed, that means you can't catch it.
2. The throw in constructor is removed.
Now the stack trace will print "Exception from method" and "Suppressed: Exception from closeable" below. Here you also can't catch the suppressed exception thrown by close method, but you will be nofitied about the suppressed exception.
3. Throws from constructor and method are removed.
As you have probably already guessed the "Exception from closeable" will be printed.
Important tip: In all of above situations you are actually catching all exceptions, no matter where they were throwed. So if you use try-with-resource block you don't need to wrap the block with another try-catch, the extra block is simply useless.
Hope it helps :)
I would suggest using a flag as in the following example:
static String getData() throws IOException {
boolean isTryCompleted = false;
String theData = null;
try (MyResource br = new MyResource();) {
theData = br.getData();
isTryCompleted = true;
} catch(IOException e) {
if (!isTryCompleted )
throw e;
// else it's a close exception and it can be ignored
}
return theData;
}
source:Close resource quietly using try-with-resources