Reputation: 565
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
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
Reputation: 308021
That needs three slightly different answers:
Yes, you can wrap an exception in another exception of the same type.
No, you can't wrap an exception in itself (i.e. in the exact same instance).
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
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