Arjit
Arjit

Reputation: 565

Can we wrap an Exception with its own in java

Can I create a Exception like

A a = new A (new B ( new A ) );

where A and B are two different type of Exception.

I know Java can do it but is it right to do that ?

Edit : I am writing an retry on type of Exception so I am checking the getCause of the Exception. I am breaking when getCause is null or getCause equal itself , Should I also break when getCause equals any Exception seen so far

Upvotes: 0

Views: 465

Answers (3)

Stephen C
Stephen C

Reputation: 718768

AException a = new AException (new BException ( new AException ) );

This is legal.


You can also initialize the cause directly using the initCause(Throwable) method.

If you try to make exception its own cause; e.g.

 AException a = new AException();
 a.initCause(a);

you will get an IllegalArgumentException("Self-causation not permitted"). (Thanks to Joachim Sauer for pointing that out.)

While, the JVM will not stop you creating an indirect cycle, it is a really bad idea nonetheless.

  • It is an abuse of the Throwable API. It makes no logical sense for an exceptional event to have caused itself, directly or indirectly.

  • There is likely be code out there that assumes that the "cause" chain of an exception doesn't have any cycles. Such code is likely to fail in a nasty way if it ever encounters a pathological exception with a cause cycle.

Note that current generation (Java 7) printStackTrace() detects and deals with a "cause" cycles, but earlier generations did not:

Upvotes: 4

Joachim Sauer
Joachim Sauer

Reputation: 308021

That needs three slightly different answers:

  1. Yes, you can wrap an exception in another exception of the same type.

  2. No, you can't wrap an exception in itself (i.e. in the exact same instance).

  3. Unfortunately yes, you can create a loop (A causing B causing A causing B ...).

The first one is pretty clear: you can wrap an IllegalStateException wrapping an IllegalArgumentException caused by another IllegalStateException.

The second one is prevented by the code in initClause() (which is called by the constructor or can be called directly if it was never called before), that prevents self-causation (indeed cause == this is used as a flag that no cause was set, to distinguish it from cause == null which means the cause was explicitly set to null).

The third bit is bad, but shouldn't happen too often in practice, as you'd have to do some extra work to get it:

Exception e1 = new Exception();
Exception e2 = new Exception(e1);
e1.initCause(e2);

Luckily printStackTrace() actually handles that case:

java.lang.Exception: java.lang.Exception
    at ScratchMain.main(ScratchMain.java:6)
Caused by: java.lang.Exception
    at ScratchMain.main(ScratchMain.java:5)
    [CIRCULAR REFERENCE:java.lang.Exception: java.lang.Exception]

Upvotes: 1

Amit Deshpande
Amit Deshpande

Reputation: 19185

Consider you have following classes.

public static class A extends Exception {
    public A() {}
    public A(Exception e) {}

}
public static class B extends Exception {
    public B(Exception e) {}
    public B() {}
}

Now if you see there is always end to wrapped exceptions when you appears at default constructor. Until then you should call getCause()

 throw new B(new A(new B()));//Ends with B since no exception is wrapped inside it.

Upvotes: 1

Related Questions