Related
How can I use JUnit idiomatically to test that some code throws an exception?
While I can certainly do something like this:
#Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
I recall that there is an annotation or an Assert.xyz or something that is far less kludgy and far more in-the-spirit of JUnit for these sorts of situations.
It depends on the JUnit version and what assert libraries you use.
For JUnit5 and 4.13 see answer
If you use AssertJ or google-truth, see answer
The original answer for JUnit <= 4.12 was:
#Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
ArrayList emptyList = new ArrayList();
Object o = emptyList.get(0);
}
Though answer has more options for JUnit <= 4.12.
Reference:
JUnit Test-FAQ
Edit: Now that JUnit 5 and JUnit 4.13 have been released, the best option would be to use Assertions.assertThrows() (for JUnit 5) and Assert.assertThrows() (for JUnit 4.13+). See my other answer for details.
If you haven't migrated to JUnit 5, but can use JUnit 4.7, you can use the ExpectedException Rule:
public class FooTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
exception.expect(IndexOutOfBoundsException.class);
foo.doStuff();
}
}
This is much better than #Test(expected=IndexOutOfBoundsException.class) because the test will fail if IndexOutOfBoundsException is thrown before foo.doStuff()
See this article for details.
Be careful using expected exception, because it only asserts that the method threw that exception, not a particular line of code in the test.
I tend to use this for testing parameter validation, because such methods are usually very simple, but more complex tests might better be served with:
try {
methodThatShouldThrow();
fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}
Apply judgement.
in junit, there are four ways to test exception.
junit5.x
for junit5.x, you can use assertThrows as following
#Test
public void testFooThrowsIndexOutOfBoundsException() {
Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
assertEquals("expected messages", exception.getMessage());
}
junit4.x
for junit4.x, use the optional 'expected' attribute of Test annonation
#Test(expected = IndexOutOfBoundsException.class)
public void testFooThrowsIndexOutOfBoundsException() {
foo.doStuff();
}
for junit4.x, use the ExpectedException rule
public class XxxTest {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void testFooThrowsIndexOutOfBoundsException() {
thrown.expect(IndexOutOfBoundsException.class)
//you can test the exception message like
thrown.expectMessage("expected messages");
foo.doStuff();
}
}
you also can use the classic try/catch way widely used under junit 3 framework
#Test
public void testFooThrowsIndexOutOfBoundsException() {
try {
foo.doStuff();
fail("expected exception was not occured.");
} catch(IndexOutOfBoundsException e) {
//if execution reaches here,
//it indicates this exception was occured.
//so we need not handle it.
}
}
so
if you like junit 5, then you should like the 1st one
the 2nd way is used when you only want test the type of exception
the first and last two are used when you want test exception message further
if you use junit 3, then the 4th one is preferred
for more info, you can read this document and junit5 user guide for details.
As answered before, there are many ways of dealing with exceptions in JUnit. But with Java 8 there is another one: using Lambda Expressions. With Lambda Expressions we can achieve a syntax like this:
#Test
public void verifiesTypeAndMessage() {
assertThrown(new DummyService()::someMethod)
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasMessageStartingWith("Runtime")
.hasMessageEndingWith("occurred")
.hasMessageContaining("exception")
.hasNoCause();
}
assertThrown accepts a functional interface, whose instances can be created with lambda expressions, method references, or constructor references. assertThrown accepting that interface will expect and be ready to handle an exception.
This is relatively simple yet powerful technique.
Have a look at this blog post describing this technique: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
The source code can be found here: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8
Disclosure: I am the author of the blog and the project.
tl;dr
post-JDK8 : Use AssertJ or custom lambdas to assert exceptional behaviour.
pre-JDK8 : I will recommend the old good try-catch block. (Don't forget to add a fail() assertion before the catch block)
Regardless of Junit 4 or JUnit 5.
the long story
It is possible to write yourself a do it yourself try-catch block or use the JUnit tools (#Test(expected = ...) or the #Rule ExpectedException JUnit rule feature).
But these ways are not so elegant and don't mix well readability wise with other tools. Moreover, JUnit tooling does have some pitfalls.
The try-catch block you have to write the block around the tested behavior and write the assertion in the catch block, that may be fine but many find that this style interrupts the reading flow of a test. Also, you need to write an Assert.fail at the end of the try block. Otherwise, the test may miss one side of the assertions; PMD, findbugs or Sonar will spot such issues.
The #Test(expected = ...) feature is interesting as you can write less code and then writing this test is supposedly less prone to coding errors. But this approach is lacking in some areas.
If the test needs to check additional things on the exception like the cause or the message (good exception messages are really important, having a precise exception type may not be enough).
Also as the expectation is placed around in the method, depending on how the tested code is written then the wrong part of the test code can throw the exception, leading to false-positive test and I'm not sure that PMD, findbugs or Sonar will give hints on such code.
#Test(expected = WantedException.class)
public void call2_should_throw_a_WantedException__not_call1() {
// init tested
tested.call1(); // may throw a WantedException
// call to be actually tested
tested.call2(); // the call that is supposed to raise an exception
}
The ExpectedException rule is also an attempt to fix the previous caveats, but it feels a bit awkward to use as it uses an expectation style, EasyMock users know very well this style. It might be convenient for some, but if you follow Behaviour Driven Development (BDD) or Arrange Act Assert (AAA) principles the ExpectedException rule won't fit in those writing style. Aside from that it may suffer from the same issue as the #Test way, depending on where you place the expectation.
#Rule ExpectedException thrown = ExpectedException.none()
#Test
public void call2_should_throw_a_WantedException__not_call1() {
// expectations
thrown.expect(WantedException.class);
thrown.expectMessage("boom");
// init tested
tested.call1(); // may throw a WantedException
// call to be actually tested
tested.call2(); // the call that is supposed to raise an exception
}
Even the expected exception is placed before the test statement, it breaks your reading flow if the tests follow BDD or AAA.
Also, see this comment issue on JUnit of the author of ExpectedException. JUnit 4.13-beta-2 even deprecates this mechanism:
Pull request #1519: Deprecate ExpectedException
The method Assert.assertThrows provides a nicer way for verifying exceptions. In addition, the use of ExpectedException is error-prone when used with other rules like TestWatcher because the order of rules is important in that case.
So these above options have all their load of caveats, and clearly not immune to coder errors.
There's a project I became aware of after creating this answer that looks promising, it's catch-exception.
As the description of the project says, it let a coder write in a fluent line of code catching the exception and offer this exception for the latter assertion. And you can use any assertion library like Hamcrest or AssertJ.
A rapid example taken from the home page :
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
when(myList).get(1);
// then: we expect an IndexOutOfBoundsException
then(caughtException())
.isInstanceOf(IndexOutOfBoundsException.class)
.hasMessage("Index: 1, Size: 0")
.hasNoCause();
As you can see the code is really straightforward, you catch the exception on a specific line, the then API is an alias that will use AssertJ APIs (similar to using assertThat(ex).hasNoCause()...). At some point the project relied on FEST-Assert the ancestor of AssertJ. EDIT: It seems the project is brewing a Java 8 Lambdas support.
Currently, this library has two shortcomings :
At the time of this writing, it is noteworthy to say this library is based on Mockito 1.x as it creates a mock of the tested object behind the scene. As Mockito is still not updated this library cannot work with final classes or final methods. And even if it was based on Mockito 2 in the current version, this would require to declare a global mock maker (inline-mock-maker), something that may not what you want, as this mock maker has different drawbacks that the regular mock maker.
It requires yet another test dependency.
These issues won't apply once the library supports lambdas. However, the functionality will be duplicated by the AssertJ toolset.
Taking all into account if you don't want to use the catch-exception tool, I will recommend the old good way of the try-catch block, at least up to the JDK7. And for JDK 8 users you might prefer to use AssertJ as it offers may more than just asserting exceptions.
With the JDK8, lambdas enter the test scene, and they have proved to be an interesting way to assert exceptional behaviour. AssertJ has been updated to provide a nice fluent API to assert exceptional behaviour.
And a sample test with AssertJ :
#Test
public void test_exception_approach_1() {
...
assertThatExceptionOfType(IOException.class)
.isThrownBy(() -> someBadIOOperation())
.withMessage("boom!");
}
#Test
public void test_exception_approach_2() {
...
assertThatThrownBy(() -> someBadIOOperation())
.isInstanceOf(Exception.class)
.hasMessageContaining("boom");
}
#Test
public void test_exception_approach_3() {
...
// when
Throwable thrown = catchThrowable(() -> someBadIOOperation());
// then
assertThat(thrown).isInstanceOf(Exception.class)
.hasMessageContaining("boom");
}
With a near-complete rewrite of JUnit 5, assertions have been improved a bit, they may prove interesting as an out of the box way to assert properly exception. But really the assertion API is still a bit poor, there's nothing outside assertThrows.
#Test
#DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
Assertions.assertEquals("...", t.getMessage());
}
As you noticed assertEquals is still returning void, and as such doesn't allow chaining assertions like AssertJ.
Also if you remember name clash with Matcher or Assert, be prepared to meet the same clash with Assertions.
I'd like to conclude that today (2017-03-03) AssertJ's ease of use, discoverable API, the rapid pace of development and as a de facto test dependency is the best solution with JDK8 regardless of the test framework (JUnit or not), prior JDKs should instead rely on try-catch blocks even if they feel clunky.
This answer has been copied from another question that don't have the same visibility, I am the same author.
Now that JUnit 5 and JUnit 4.13 have been released, the best option would be to use Assertions.assertThrows() (for JUnit 5) and Assert.assertThrows() (for JUnit 4.13). See
the JUnit 5 User Guide.
Here is an example that verifies an exception is thrown, and uses Truth to make assertions on the exception message:
public class FooTest {
#Test
public void doStuffThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
IndexOutOfBoundsException e = assertThrows(
IndexOutOfBoundsException.class, foo::doStuff);
assertThat(e).hasMessageThat().contains("woops!");
}
}
The advantages over the approaches in the other answers are:
Built into JUnit
You get a useful exception message if the code in the lambda doesn't throw an exception, and a stacktrace if it throws a different exception
Concise
Allows your tests to follow Arrange-Act-Assert
You can precisely indicate what code you are expecting to throw the exception
You don't need to list the expected exception in the throws clause
You can use the assertion framework of your choice to make assertions about the caught exception
Update: JUnit5 has an improvement for exceptions testing: assertThrows.
The following example is from: Junit 5 User Guide
import static org.junit.jupiter.api.Assertions.assertThrows;
#Test
void exceptionTesting() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
Original answer using JUnit 4.
There are several ways to test that an exception is thrown. I have also discussed the below options in my post How to write great unit tests with JUnit
Set the expected parameter #Test(expected = FileNotFoundException.class).
#Test(expected = FileNotFoundException.class)
public void testReadFile() {
myClass.readFile("test.txt");
}
Using try catch
public void testReadFile() {
try {
myClass.readFile("test.txt");
fail("Expected a FileNotFoundException to be thrown");
} catch (FileNotFoundException e) {
assertThat(e.getMessage(), is("The file test.txt does not exist!"));
}
}
Testing with ExpectedException Rule.
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void testReadFile() throws FileNotFoundException {
thrown.expect(FileNotFoundException.class);
thrown.expectMessage(startsWith("The file test.txt"));
myClass.readFile("test.txt");
}
You could read more about exceptions testing in JUnit4 wiki for Exception testing and bad.robot - Expecting Exceptions JUnit Rule.
How about this: catch a very general exception, make sure it makes it out of the catch block, then assert that the class of the exception is what you expect it to be. This assert will fail if a) the exception is of the wrong type (eg. if you got a Null Pointer instead) and b) the exception wasn't ever thrown.
public void testFooThrowsIndexOutOfBoundsException() {
Throwable e = null;
try {
foo.doStuff();
} catch (Throwable ex) {
e = ex;
}
assertTrue(e instanceof IndexOutOfBoundsException);
}
Using an AssertJ assertion, which can be used alongside JUnit:
import static org.assertj.core.api.Assertions.*;
#Test
public void testFooThrowsIndexOutOfBoundsException() {
Foo foo = new Foo();
assertThatThrownBy(() -> foo.doStuff())
.isInstanceOf(IndexOutOfBoundsException.class);
}
It's better than #Test(expected=IndexOutOfBoundsException.class) because it guarantees the expected line in the test threw the exception and lets you check more details about the exception, such as message, easier:
assertThatThrownBy(() ->
{
throw new Exception("boom!");
})
.isInstanceOf(Exception.class)
.hasMessageContaining("boom");
Maven/Gradle instructions here.
BDD Style Solution: JUnit 4 + Catch Exception + AssertJ
import static com.googlecode.catchexception.apis.BDDCatchException.*;
#Test
public void testFooThrowsIndexOutOfBoundsException() {
when(() -> foo.doStuff());
then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);
}
Dependencies
eu.codearte.catch-exception:catch-exception:2.0
To solve the same problem I did set up a small project:
http://code.google.com/p/catch-exception/
Using this little helper you would write
verifyException(foo, IndexOutOfBoundsException.class).doStuff();
This is less verbose than the ExpectedException rule of JUnit 4.7.
In comparison to the solution provided by skaffman, you can specify in which line of code you expect the exception. I hope this helps.
You can also do this:
#Test
public void testFooThrowsIndexOutOfBoundsException() {
try {
foo.doStuff();
assert false;
} catch (IndexOutOfBoundsException e) {
assert true;
}
}
IMHO, the best way to check for exceptions in JUnit is the try/catch/fail/assert pattern:
// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
sut.doThing();
fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
// otherwise you may catch an exception for a dependency unexpectedly
// a strong assertion on the message,
// in case the exception comes from anywhere an unexpected line of code,
// especially important if your checking IllegalArgumentExceptions
assertEquals("the message I get", e.getMessage());
}
The assertTrue might be a bit strong for some people, so assertThat(e.getMessage(), containsString("the message"); might be preferable.
JUnit 5 Solution
import static org.junit.jupiter.api.Assertions.assertThrows;
#Test
void testFooThrowsIndexOutOfBoundsException() {
IndexOutOfBoundsException exception = expectThrows(IndexOutOfBoundsException.class, foo::doStuff);
assertEquals("some message", exception.getMessage());
}
More Infos about JUnit 5 on http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
The most flexible and elegant answer for Junit 4 I found in the Mkyong blog. It has the flexibility of the try/catch using the #Rule annotation. I like this approach because you can read specific attributes of a customized exception.
package com.mkyong;
import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;
public class Exception3Test {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Test
public void testNameNotFoundException() throws NameNotFoundException {
//test specific type of exception
thrown.expect(NameNotFoundException.class);
//test message
thrown.expectMessage(is("Name is empty!"));
//test detail
thrown.expect(hasProperty("errCode")); //make sure getters n setters are defined.
thrown.expect(hasProperty("errCode", is(666)));
CustomerService cust = new CustomerService();
cust.findByName("");
}
}
I tried many of the methods here, but they were either complicated or didn't quite meet my requirements. In fact, one can write a helper method quite simply:
public class ExceptionAssertions {
public static void assertException(BlastContainer blastContainer ) {
boolean caughtException = false;
try {
blastContainer.test();
} catch( Exception e ) {
caughtException = true;
}
if( !caughtException ) {
throw new AssertionFailedError("exception expected to be thrown, but was not");
}
}
public static interface BlastContainer {
public void test() throws Exception;
}
}
Use it like this:
assertException(new BlastContainer() {
#Override
public void test() throws Exception {
doSomethingThatShouldExceptHere();
}
});
Zero dependencies: no need for mockito, no need powermock; and works just fine with final classes.
JUnit has built-in support for this, with an "expected" attribute.
Java 8 solution
If you would like a solution which:
Utilizes Java 8 lambdas
Does not depend on any JUnit magic
Allows you to check for multiple exceptions within a single test method
Checks for an exception being thrown by a specific set of lines within your test method instead of any unknown line in the entire test method
Yields the actual exception object that was thrown so that you can further examine it
Here is a utility function that I wrote:
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause(); //allows testing for "assert x != null : new IllegalArgumentException();"
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
#SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
(taken from my blog)
Use it as follows:
#Test
public void testMyFunction()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
myFunction();
} );
assert e.getMessage().equals( "I haz fail!" );
}
public void myFunction()
{
throw new RuntimeException( "I haz fail!" );
}
In my case I always get RuntimeException from db, but messages differ. And exception need to be handled respectively. Here is how I tested it:
#Test
public void testThrowsExceptionWhenWrongSku() {
// Given
String articleSimpleSku = "999-999";
int amountOfTransactions = 1;
Exception exception = null;
// When
try {
createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
} catch (RuntimeException e) {
exception = e;
}
// Then
shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}
private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
assertNotNull(e);
assertTrue(e.getMessage().contains(message));
}
Just make a Matcher that can be turned off and on, like this:
public class ExceptionMatcher extends BaseMatcher<Throwable> {
private boolean active = true;
private Class<? extends Throwable> throwable;
public ExceptionMatcher(Class<? extends Throwable> throwable) {
this.throwable = throwable;
}
public void on() {
this.active = true;
}
public void off() {
this.active = false;
}
#Override
public boolean matches(Object object) {
return active && throwable.isAssignableFrom(object.getClass());
}
#Override
public void describeTo(Description description) {
description.appendText("not the covered exception type");
}
}
To use it:
add public ExpectedException exception = ExpectedException.none();,
then:
ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();
In JUnit 4 or later you can test the exceptions as follows
#Rule
public ExpectedException exceptions = ExpectedException.none();
this provides a lot of features which can be used to improve our JUnit tests. If you see the below example I am testing 3 things on the exception.
The Type of exception thrown
The exception Message
The cause of the exception
public class MyTest {
#Rule
public ExpectedException exceptions = ExpectedException.none();
ClassUnderTest classUnderTest;
#Before
public void setUp() throws Exception {
classUnderTest = new ClassUnderTest();
}
#Test
public void testAppleisSweetAndRed() throws Exception {
exceptions.expect(Exception.class);
exceptions.expectMessage("this is the exception message");
exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));
classUnderTest.methodUnderTest("param1", "param2");
}
}
We can use an assertion fail after the method that must return an exception:
try{
methodThatThrowMyException();
Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
// Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
// In case of verifying the error message
MyException myException = (MyException) exception;
assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}
Additionally to what NamShubWriter has said, make sure that:
The ExpectedException instance is public (Related Question)
The ExpectedException isn't instantiated in say, the #Before method. This post clearly explains all the intricacies of JUnit's order of execution.
Do not do this:
#Rule
public ExpectedException expectedException;
#Before
public void setup()
{
expectedException = ExpectedException.none();
}
Finally, this blog post clearly illustrates how to assert that a certain exception is thrown.
Junit4 solution with Java8 is to use this function:
public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
try {
funky.call();
} catch (Throwable e) {
if (expectedException.isInstance(e)) {
return e;
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
}
throw new AssertionError(
String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}
Usage is then:
assertThrows(ValidationException.class,
() -> finalObject.checkSomething(null));
Note that the only limitation is to use a final object reference in lambda expression.
This solution allows to continue test assertions instead of expecting thowable at method level using #Test(expected = IndexOutOfBoundsException.class) solution.
I recomend library assertj-core to handle exception in junit test
In java 8, like this:
//given
//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));
//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);
JUnit framework has assertThrows() method:
ArithmeticException exception = assertThrows(ArithmeticException.class, () ->
calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
for JUnit 5 it's in org.junit.jupiter.api.Assertions class;
for JUnit 4.13 it's in org.junit.Assert class;
for earlier versions of JUnit 4: just add reference on org.junit.jupiter:junit-jupiter-api to your project and you'll get perfectly well working version from JUnit 5.
Take for example, you want to write Junit for below mentioned code fragment
public int divideByZeroDemo(int a,int b){
return a/b;
}
public void exceptionWithMessage(String [] arr){
throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}
The above code is to test for some unknown exception that may occur and the below one is to assert some exception with custom message.
#Rule
public ExpectedException exception=ExpectedException.none();
private Demo demo;
#Before
public void setup(){
demo=new Demo();
}
#Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {
demo.divideByZeroDemo(5, 0);
}
#Test
public void testExceptionWithMessage(){
exception.expectMessage("Array is out of bound");
exception.expect(ArrayIndexOutOfBoundsException.class);
demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}
With Java 8 you can create a method taking a code to check and expected exception as parameters:
private void expectException(Runnable r, Class<?> clazz) {
try {
r.run();
fail("Expected: " + clazz.getSimpleName() + " but not thrown");
} catch (Exception e) {
if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
}
}
and then inside your test:
expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);
Benefits:
not relying on any library
localised check - more precise and allows to have multiple assertions like this within one test if needed
easy to use
#Test(expectedException=IndexOutOfBoundsException.class)
public void testFooThrowsIndexOutOfBoundsException() throws Exception {
doThrow(IndexOutOfBoundsException.class).when(foo).doStuff();
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
assertEquals(IndexOutOfBoundsException .class, ex.getCause().getClass());
throw e;
}
}
Here is another way to check method thrown correct exception or not.
Some 3rd party library swallowed an Exception:
String getAnswer(){
try{
// do stuff, modify instance state, maybe throw some exceptions
// ...
return computeAnswer();
}catch (SomeException e){
return null;
}
}
As much as I want to change it into:
String getAnswer() throws SomeException{
// do stuff, modify instance state, maybe throw some exceptions
// ...
return computeAnswer();
}
I can't, because the library is already packaged into a jar. So, is there a way to bring the exception back?
I don't need to rethrow, a stacktrace with exception and message would work too.
I don't think reflection would help here, Unsafe perhaps?
Yes I know I can use a debugger to find out what's happening, but that wouldn't be very useful if I need the exception at runtime for logging and stuff like that
You can do it without reflection or AOP. The main idea is to throw another (unchecked) exception in the constructor of SomeException. There are some limitations (see at the end of this answer) but I hope it fits your needs.
You need to replace the SomeException with a new version (just create a SomeException.java file in the original package but in your src directory) with something like :
package com.3rdpartylibrary;
public class SomeException extends Exception {
public static class SomeExceptionWrapperException extends RuntimeException {
public SomeExceptionWrapperException(final SomeException ex) {
super(ex.getMessage(), ex);
}
}
public SomeException(final String message) {
super(message);
throw new SomeExceptionWrapperException(this); //<=== the key is here
}
}
The SomeExceptionWrapperException has to be unchecked (inherit from RuntimeException or Error). It will be our wrapper to carry the SomeException accross the ugly 3rd party catch(...)
Then you can catch the SomeExceptionWrapperException in your code (and eventually rethrow the original SomeException:
//original, unmodifiable 3rdParty code, here as a example
public String getAnswer() {
try {
//some code
throw new SomeException("a message");
} catch (final SomeException e) {
return null;
}
}
//a wrapper to getAnswer to unwrapp the `SomeException`
public String getAnswerWrapped() throws SomeException {
try {
return getAnswer();
} catch (final SomeExceptionWrapperException e) {
throw (SomeException) e.getCause();
}
}
#Test(expected = SomeException.class)
public void testThrow() throws SomeException {
final String t = getAnswerWrapped();
}
The test will be green as the original SomeException, will be thrown.
Limitations:
This solution will not work if either :
if SomeException is in java.lang as you cannot replace java.lang classes (or see Replacing java class?)
if the 3rd party method has a catch(Throwable e) (which will be horrible and should motivate you to ignore the full 3rd party library)
To solve this based on your constraints I would use aspects (something like AspectJ) and attach it to the creation of your exception, logging (or having it call some arbitrary) method then.
http://www.ibm.com/developerworks/library/j-aspectj/
If all you're looking for is to log the stacktrace + exception message, you could do that at the point you're throwing your exception.
See Get current stack trace in Java to get the stack trace. You can simply use Throwable.getMessage() to get the message and write it out.
But if you need the actual Exception within your code, you could try and add the exception into a ThreadLocal.
To do this, you would need a class like this that can store the exception:
package threadLocalExample;
public class ExceptionKeeper
{
private static ThreadLocal<Exception> threadLocalKeeper = new ThreadLocal<Exception>();
public static Exception getException()
{
return threadLocalKeeper.get();
}
public static void setException(Exception e)
{
threadLocalKeeper.set(e);
}
public static void clearException()
{
threadLocalKeeper.set(null);
}
}
... then in your code which throws the Exception, the code that the 3rd party library calls, you can do something like this to record the exception before you throw it:
package threadLocalExample;
public class ExceptionThrower
{
public ExceptionThrower()
{
super();
}
public void doSomethingInYourCode() throws SomeException
{
boolean someBadThing = true;
if (someBadThing)
{
// this is bad, need to throw an exception!
SomeException e = new SomeException("Message Text");
// but first, store it in a ThreadLocal because that 3rd party
// library I use eats it
ExceptionKeeper.setException(e);
// Throw the exception anyway - hopefully the library will be fixed
throw e;
}
}
}
... then in your overall code, the one that calls the third party library, it can setup and use the ThreadLocal class like this:
package threadLocalExample;
import thirdpartylibrary.ExceptionEater;
public class MainPartOfTheProgram
{
public static void main(String[] args)
{
// call the 3rd party library function that eats exceptions
// but first, prepare the exception keeper - clear out any data it may have
// (may not need to, but good measure)
ExceptionKeeper.clearException();
try
{
// now call the exception eater. It will eat the exception, but the ExceptionKeeper
// will have it
ExceptionEater exEater = new ExceptionEater();
exEater.callSomeThirdPartyLibraryFunction();
// check the ExceptionKeeper for the exception
Exception ex = ExceptionKeeper.getException();
if (ex != null)
{
System.out.println("Aha! The library ate my exception, but I found it");
}
}
finally
{
// Wipe out any data in the ExceptionKeeper. ThreadLocals are real good
// ways of creating memory leaks, and you would want to start from scratch
// next time anyway.
ExceptionKeeper.clearException();
}
}
}
Beware of ThreadLocals. They have their use, but they are a great way of creating memory leaks. So if your application has a lot of threads that would execute this code, be sure to look at the memory footprint and make sure the ThreadLocals aren't taking up too much memory. Being sure to clear out the ThreadLocal's data when you know you no longer need it should prevent that.
JVMTI agent can help. See the related question.
I've made an agent that calls Throwable.printStackTrace() for every thrown exception, but you may easily change the callback to invoke any other Java method.
A rather dirty trick that could do the job with less effort than AOP or de-/recompile the JAR:
If you can copy the source code, you can create a patched version of the class in question with your version of the getAnswer method. Then put it on your classpath before the third party library that contains the unwanted version of getAnswer.
Problems could arise if SomeException is not a RuntimeException and other third party code calls getAnswer. In this situation I am not sure how the resulting behavior will be. But you could circumvent this by wrapping SomeException in a custom RuntimeException.
Could you not just use a reference variable to call that method, if the result is a null, then you can just display a message/call an exception, whatever you want?
if you're using maven, you would exclude packages of the library.
Dependency Exclusions.
I hope to be helpful
If you have the source to the throwing class, you can add it "in the original package but in your src directory" using the technique as #Benoît has pointed out. Then just change
return null;
to
return e;
or
e.printStackTrace();
etc.
This would be quicker then making a new Exception.
In Java, is it possible to make a method that has a throws statement to be not checked.
For example:
public class TestClass {
public static void throwAnException() throws Exception {
throw new Exception();
}
public static void makeNullPointer() {
Object o = null;
o.equals(0);//NullPointerException
}
public static void exceptionTest() {
makeNullPointer(); //The compiler allows me not to check this
throwAnException(); //I'm forced to handle the exception, but I don't want to
}
}
You can try and do nothing about it:
public static void exceptionTest() {
makeNullPointer(); //The compiler allows me not to check this
try {
throwAnException(); //I'm forced to handle the exception, but I don't want to
} catch (Exception e) { /* do nothing */ }
}
Bear in mind, in real life this is extemely ill-advised. That can hide an error and keep you searching for dogs a whole week while the problem was really a cat(ch). (Come on, put at least a System.err.println() there - Logging is the best practice here, as suggested by #BaileyS.)
Unchecked exceptions in Java extend the RuntimeException class. Throwing them will not demand a catch from their clients:
// notice there's no "throws RuntimeException" at the signature of this method
public static void someMethodThatThrowsRuntimeException() /* no need for throws here */ {
throw new RuntimeException();
}
Classes that extend RuntimeException won't require a throws declaration as well.
And a word from Oracle about it:
Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.
There are 3 things you can do :
Throw a RuntimeException (or something extending a RuntimeException, like NullPointerException, IllegalArgumentException,...), you don't have to catch these as they are unchecked exceptions.
Catch the exception and do nothing (not recommended) :
public static void exceptionTest() {
makeNullPointer(); //The compiler allows me not to check this
try {
throwAnException(); //I'm forced to handle the exception, but I don't want to
} catch (Exception e) {
// Do nothing
}
}
Change exceptionTest () declaration to say that it throws an Exception, and let the method calling it catch the Exception and do what is appropriate :
public static void exceptionTest() throws Exception {
makeNullPointer(); //The compiler allows me not to check this
throwAnException(); //I'm no more forced to handle the exception
}
In Java there is two kinds of Exceptions, Checked Exceptions and Unchecked Exceptions.
Exception is a checked exception, must caught or thrown.
NullPointerException is a RuntimeException, (the compiler doesn’t forces them to be declared in the throws claus) you can ignore it, ,but it still may occur in the Runtime, and your application will crash.
From Exception documentation:
The class Exception and any subclasses that are not also subclasses of
RuntimeException are checked exceptions. Checked exceptions need to be
declared in a method or constructor's throws clause if they can be
thrown by the execution of the method or constructor and propagate
outside the method or constructor boundary.
From the RuntimeException documentation:
RuntimeException is the superclass of those exceptions that can be
thrown during the normal operation of the Java Virtual Machine.
RuntimeException and its subclasses are unchecked exceptions.
Unchecked exceptions do not need to be declared in a method or
constructor's throws clause if they can be thrown by the execution of
the method or constructor and propagate outside the method or
constructor boundary.
No, it raises a compiler error. Being a checked exception, you must either catch it or propagate it by declaring your method as potentially throwing it.
Check this and this.
Throw a RuntimeException or an exception which is derived from RuntimeException. Then the compiler will not force you to catch it.
The other answers are right, in that they correctly tell you what you should do, but it is actually possible to throw a undeclared checked exception. There are a few ways this can be done; the simplest is:
public void methodThatSecretlyThrowsAnException() {
Thread.currentThread().stop(new Exception());
}
or if your goal is to wrap an existing method that does declare its exception
public void methodThatSecretlyThrowsAnException() {
try {
methodThatAdmitsItThrowsAnException();
} catch(final Exception e) {
Thread.currentThread().stop(e);
}
}
(Needless to say, you should never do this.)
Just catch an exception and dont do any thing with it, leave it as it is and catch the generic exception in case you are not aware of the specific exception
try{
//Your logic goes here
}
catch(Exception e)//Exception is generic
{
//do nothing
}
AS I know, it's impossible in the case. Only unchecked exception, compiler can skip to check. such as RuntimeException.
You can use a loophole in the Java Compiler. Add the following code:
public RuntimeException hideThrow(Throwable e) {
if (e == null)
throw new NullPointerException("e");
this.<RuntimeException>hideThrow0(e);
return null;
}
#SuppressWarnings("unchecked")
private <GenericThrowable extends Throwable> void hideThrow0(Throwable e) throws GenericThrowable {
throw (GenericThrowable) e;
}
You can catch the exception, then invoke hideThrow with the exception to throw it without the compiler noticing. This works because of type erasure. At compile time, GenericThrowable represents RuntimeException because that is what we are passing. At run time, GenericThrowable represents Throwable because that is the basic type in the type parameter specification.
It is not advisable to avoid an exception with an empty catch block even though you are completely sure that is not going to fail under any circumstance. Sometimes, we are not aware of the human factor.
If you are sure that an exception is very unlikely to happen (if not impossible) you should create your own Exception and and wrap the unexpected exception in it.
For example:
private class UnlikelyException extends RuntimeException {
public UnlikelyException (Exception e){
super (e);
}
}
Then wrap your code with a try-catch block and throw your exception, which you don't have to catch
try {
// Your code
} catch (Exception e) {
throw new UnlikelyException(e);
}
Is it possible to construct a snippet of code in Java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
Thoughts that came to mind are using for example interceptors or aspect-oriented programming.
I haven't tried this, so I don't know if the JVM would restrict something like this, but maybe you could compile code which throws ChuckNorrisException, but at runtime provide a class definition of ChuckNorrisException which does not extend Throwable.
UPDATE:
It doesn't work. It generates a verifier error:
Exception in thread "main" java.lang.VerifyError: (class: TestThrow, method: ma\
in signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestThrow. Program will exit.
UPDATE 2:
Actually, you can get this to work if you disable the byte code verifier! (-Xverify:none)
UPDATE 3:
For those following from home, here is the full script:
Create the following classes:
public class ChuckNorrisException
extends RuntimeException // <- Comment out this line on second compilation
{
public ChuckNorrisException() { }
}
public class TestVillain {
public static void main(String[] args) {
try {
throw new ChuckNorrisException();
}
catch(Throwable t) {
System.out.println("Gotcha!");
}
finally {
System.out.println("The end.");
}
}
}
Compile classes:
javac -cp . TestVillain.java ChuckNorrisException.java
Run:
java -cp . TestVillain
Gotcha!
The end.
Comment out "extends RuntimeException" and recompile ChuckNorrisException.java only :
javac -cp . ChuckNorrisException.java
Run:
java -cp . TestVillain
Exception in thread "main" java.lang.VerifyError: (class: TestVillain, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestVillain. Program will exit.
Run without verification:
java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
After having pondered this, I have successfully created an uncatchable exception. I chose to name it JulesWinnfield, however, rather than Chuck, because it is one mushroom-cloud-laying-mother-exception. Furthermore, it might not be exactly what you had in mind, but it certainly can't be caught. Observe:
public static class JulesWinnfield extends Exception
{
JulesWinnfield()
{
System.err.println("Say 'What' again! I dare you! I double dare you!");
System.exit(25-17); // And you shall know I am the LORD
}
}
public static void main(String[] args)
{
try
{
throw new JulesWinnfield();
}
catch(JulesWinnfield jw)
{
System.out.println("There's a word for that Jules - a bum");
}
}
Et voila! Uncaught exception.
Output:
run:
Say 'What' again! I dare you! I double dare you!
Java Result: 8
BUILD SUCCESSFUL (total time: 0 seconds)
When I have a little more time, I'll see if I can't come up with something else, as well.
Also, check this out:
public static class JulesWinnfield extends Exception
{
JulesWinnfield() throws JulesWinnfield, VincentVega
{
throw new VincentVega();
}
}
public static class VincentVega extends Exception
{
VincentVega() throws JulesWinnfield, VincentVega
{
throw new JulesWinnfield();
}
}
public static void main(String[] args) throws VincentVega
{
try
{
throw new JulesWinnfield();
}
catch(JulesWinnfield jw)
{
}
catch(VincentVega vv)
{
}
}
Causes a stack overflow - again, exceptions remain uncaught.
With such an exception it would obviously be mandatory to use a System.exit(Integer.MIN_VALUE); from the constructor because this is what would happen if you threw such an exception ;)
Any code can catch Throwable. So no, whatever exception you create is going to be a subclass of Throwable and will be subject to being caught.
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
(Granted, technically this exception is never actually thrown, but a proper ChuckNorrisException can't be thrown -- it throws you first.)
Any exception you throw has to extend Throwable, so it can be always caught. So answer is no.
If you want to make it difficult to handle, you can override methods getCause(), getMessage(), getStackTrace(), toString() to throw another java.lang.ChuckNorrisException.
My answer is based on #jtahlborn's idea, but it's a fully working Java program, that can be packaged into a JAR file and even deployed to your favorite application server as a part of a web application.
First of all, let's define ChuckNorrisException class so that it doesn't crash JVM from the beginning (Chuck really loves crashing JVMs BTW :)
package chuck;
import java.io.PrintStream;
import java.io.PrintWriter;
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
}
#Override
public Throwable getCause() {
return null;
}
#Override
public String getMessage() {
return toString();
}
#Override
public void printStackTrace(PrintWriter s) {
super.printStackTrace(s);
}
#Override
public void printStackTrace(PrintStream s) {
super.printStackTrace(s);
}
}
Now goes Expendables class to construct it:
package chuck;
import javassist.*;
public class Expendables {
private static Class clz;
public static ChuckNorrisException getChuck() {
try {
if (clz == null) {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("chuck.ChuckNorrisException");
cc.setSuperclass(pool.get("java.lang.Object"));
clz = cc.toClass();
}
return (ChuckNorrisException)clz.newInstance();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
And finally the Main class to kick some butt:
package chuck;
public class Main {
public void roundhouseKick() throws Exception {
throw Expendables.getChuck();
}
public void foo() {
try {
roundhouseKick();
} catch (Throwable ex) {
System.out.println("Caught " + ex.toString());
}
}
public static void main(String[] args) {
try {
System.out.println("before");
new Main().foo();
System.out.println("after");
} finally {
System.out.println("finally");
}
}
}
Compile and run it with following command:
java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main
You will get following output:
before
finally
No surprise - it's a roundhouse kick after all :)
In the constructor you could start a thread which repeatedly calls originalThread.stop (ChuckNorisException.this)
The thread could catch the exception repeatedly but would keep throwing it until it dies.
No. All exceptions in Java must subclass java.lang.Throwable, and although it may not be good practice, you can catch every type of exception like so:
try {
//Stuff
} catch ( Throwable T ){
//Doesn't matter what it was, I caught it.
}
See the java.lang.Throwable documentation for more information.
If you're trying to avoid checked exceptions (ones that must be explicitly handled) then you will want to subclass Error, or RuntimeException.
Actually the accepted answer is not so nice because Java needs to be run without verification, i.e. the code would not work under normal circumstances.
AspectJ to the rescue for the real solution!
Exception class:
package de.scrum_master.app;
public class ChuckNorrisException extends RuntimeException {
public ChuckNorrisException(String message) {
super(message);
}
}
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.ChuckNorrisException;
public aspect ChuckNorrisAspect {
before(ChuckNorrisException chuck) : handler(*) && args(chuck) {
System.out.println("Somebody is trying to catch Chuck Norris - LOL!");
throw chuck;
}
}
Sample application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
catchAllMethod();
}
private static void catchAllMethod() {
try {
exceptionThrowingMethod();
}
catch (Throwable t) {
System.out.println("Gotcha, " + t.getClass().getSimpleName() + "!");
}
}
private static void exceptionThrowingMethod() {
throw new ChuckNorrisException("Catch me if you can!");
}
}
Output:
Somebody is trying to catch Chuck Norris - LOL!
Exception in thread "main" de.scrum_master.app.ChuckNorrisException: Catch me if you can!
at de.scrum_master.app.Application.exceptionThrowingMethod(Application.java:18)
at de.scrum_master.app.Application.catchAllMethod(Application.java:10)
at de.scrum_master.app.Application.main(Application.java:5)
A variant on the theme is the surprising fact that you can throw undeclared checked exceptions from Java code. Since it is not declared in the methods signature, the compiler won't let you catch the exception itself, though you can catch it as java.lang.Exception.
Here's a helper class that lets you throw anything, declared or not:
public class SneakyThrow {
public static RuntimeException sneak(Throwable t) {
throw SneakyThrow.<RuntimeException> throwGivenThrowable(t);
}
private static <T extends Throwable> RuntimeException throwGivenThrowable(Throwable t) throws T {
throw (T) t;
}
}
Now throw SneakyThrow.sneak(new ChuckNorrisException()); does throw a ChuckNorrisException, but the compiler complains in
try {
throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
about catching an exception that is not thrown if ChuckNorrisException is a checked exception.
The only ChuckNorrisExceptions in Java should be OutOfMemoryError and StackOverflowError.
You can actually "catch" them in the means that a catch(OutOfMemoryError ex) will execute in case the exception is thrown, but that block will automatically rethrow the exception to the caller.
I don't think that public class ChuckNorrisError extends Error does the trick but you could give it a try. I found no documentation about extending Error
Is it possible to construct a snippet of code in java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
Yes, and here's the answer: Design your java.lang.ChuckNorrisException such that it is not an instance of java.lang.Throwable. Why? An unthrowable object is uncatchable by definition because you can never catch something that can never be thrown.
You can keep ChuckNorris internal or private and encapsulate him or swollow him...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Two fundamental problems with exception handling in Java are that it uses the type of an exception to indicate whether action should be taken based upon it, and that anything which takes action based upon an exception (i.e. "catch"es it) is presumed to resolve the underlying condition. It would be useful to have a means by which an exception object could decide which handlers should execute, and whether the handlers that have executed so far have cleaned things up enough for the present method to satisfy its exit conditions. While this could be used to make "uncatchable" exceptions, two bigger uses would be to (1) make exceptions which will only be considered handled when they're caught by code that actually knows how to deal with them, and (2) allow for sensible handling of exceptions which occur in a finally block (if a FooException during a finally block during the unwinding of a BarException, both exceptions should propagate up the call stack; both should be catchable, but unwinding should continue until both have been caught). Unfortunately, I don't think there would be any way to make existing exception-handling code work that way without breaking things.
It is easily possible to simulate a uncaught exception on the current thread. This will trigger the regular behavior of an uncaught exception, and thus gets the job done semantically. It will, however, not necessarily stop the current thread's execution, as no exception is actually thrown.
Throwable exception = /* ... */;
Thread currentThread = Thread.currentThread();
Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
currentThread.getUncaughtExceptionHandler();
uncaughtExceptionHandler.uncaughtException(currentThread, exception);
// May be reachable, depending on the uncaught exception handler.
This is actually useful in (very rare) situations, for example when proper Error handling is required, but the method is invoked from a framework catching (and discarding) any Throwable.
Call System.exit(1) in the finalize, and just throw a copy of the exception from all the other methods, so that the program will exit.
(Late edit: This question will hopefully be obsolete when Java 7 comes, because of the "final rethrow" feature which seems like it will be added.)
Quite often, I find myself in situations looking like this:
do some initialization
try {
do some work
} catch any exception {
undo initialization
rethrow exception
}
In C# you can do it like this:
InitializeStuff();
try
{
DoSomeWork();
}
catch
{
UndoInitialize();
throw;
}
For Java, there's no good substitution, and since the proposal for improved exception handling was cut from Java 7, it looks like it'll take at best several years until we get something like it. Thus, I decided to roll my own:
(Edit: Half a year later, final rethrow is back, or so it seems.)
public final class Rethrow {
private Rethrow() { throw new AssertionError("uninstantiable"); }
/** Rethrows t if it is an unchecked exception. */
public static void unchecked(Throwable t) {
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
}
/** Rethrows t if it is an unchecked exception or an instance of E. */
public static <E extends Exception> void instanceOrUnchecked(
Class<E> exceptionClass, Throwable t) throws E, Error,
RuntimeException {
Rethrow.unchecked(t);
if (exceptionClass.isInstance(t))
throw exceptionClass.cast(t);
}
}
Typical usage:
public void doStuff() throws SomeException {
initializeStuff();
try {
doSomeWork();
} catch (Throwable t) {
undoInitialize();
Rethrow.instanceOrUnchecked(SomeException.class, t);
// We shouldn't get past the above line as only unchecked or
// SomeException exceptions are thrown in the try block, but
// we don't want to risk swallowing an error, so:
throw new SomeException("Unexpected exception", t);
}
private void doSomeWork() throws SomeException { ... }
}
It's a bit wordy, catching Throwable is usually frowned upon, I'm not really happy at using reflection just to rethrow an exception, and I always feel a bit uneasy writing "this will not happen" comments, but in practice it works well (or seems to, at least). What I wonder is:
Do I have any flaws in my rethrow helper methods? Some corner cases I've missed? (I know that the Throwable may have been caused by something so severe that my undoInitialize will fail, but that's OK.)
Has someone already invented this? I looked at Commons Lang's ExceptionUtils but that does other things.
Edit:
finally is not the droid I'm looking for. I'm only interested to do stuff when an exception is thrown.
Yes, I know catching Throwable is a big no-no, but I think it's the lesser evil here compared to having three catch clauses (for Error, RuntimeException and SomeException, respectively) with identical code.
Note that I'm not trying to suppress any errors - the idea is that any exceptions thrown in the try block will continue to bubble up through the call stack as soon as I've rewinded a few things.
There are a couple of way to handle this. The first is my preference if you don't need to know what the exception was.
boolean okay = false;
try {
// do some work which might throw an exception
okay = true;
} finally {
if (!okay) // do some clean up.
}
In some cases you can do the same without an extra variable, depending on what the try block does.
A second option is a hack but also works.
try {
// do some work which might throw an exception
} catch (Throwable t) {
// do something with t.
Thread.currentThread().stop(t);
}
The stop(Throwable t) method doesn't stop the thread, instead it causes the thread to throw the exception provided in an unchecked way.
You can use Unsafe.throwException() with a bit of fiddling and there is a way to do this with Generics which I have forgotten.
If you are that concerned about getting your uninitialization to happen then you may want to just put that code into a finally block, as, if it should be called at some point, then you perhaps should always clean up.
I am leery of catching Throwable as some of the exceptions I want to handle, and some I just log, as, there is no use passing exceptions that the user can't do anything about, such as a NullPointerException.
But, you didn't show what SomeException is defined as, but if an OutOfMemoryException is thrown, your throwable will catch it, but it may not be the same type as SomeException so your wrapper will be needed in your sample function, at least when I look at the instanceOrUnchecked method.
You may want to write a unit test, try different classes of Exceptions and see what does or doesn't work as expected, so you can document the expected behavior.
An alternative is to have a factory which creates SomeException only if the cause is a checked exception:
public static SomeException throwException(String message, Throwable cause) throws SomeException {
unchecked(cause); //calls the method you defined in the question.
throw new SomeException(message, cause);
}
The reason why I put in the return value in the method is so that the client can do something like this:
catch (Throwable e) {
undoInitialize();
throw SomeException.throwException("message", e);
}
so that the compiler is fooled into not requiring a return after the catch statement if the method has a return type, but it still throws the exception if the client forgot to put the throw before the call to the factory method.
The disadvantage of this over your code is that it is less portable (it works for SomeException, but not for SomeOtherException), but that may be ok, because it won't be for every exception type that you need to have an undo initialize.
If it fits your use case you could put the unchecked call in the constructor of SomeException and have the logic available to all subclasses, but that would have to fit your specific project - it would not be a good idea in the general case as it would prevent wrapping runtime exceptions.
public SomeException(message, cause) {
super(message, unchecked(cause));
}
private static Throwable unchecked(Throwable cause) {
if (cause instanceof Error) throw (Error) cause;
if (cause instanceof RuntimeException) throw (RuntimeException) cause;
return cause;
}