33

I have some code that might throw both checked and runtime exceptions.

I'd like to catch the checked exception and wrap it with a runtime exception. But if a RuntimeException is thrown, I don't have to wrap it as it's already a runtime exception.

The solution I have has a bit overhead and isn't "neat":

try {
  // some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
  throw e;
} catch (Exception e) {
  throw new RuntimeException(e);
}

Any idea for a more elegant way?

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
  • 6
    That's it. The only improvement on that is a higher-order function that accepts a lambda which is the `try` body and wraps it with this logic. You can check out this topic: http://stackoverflow.com/questions/31270759/a-better-approach-to-handling-exceptions-in-a-functional-way – Marko Topolnik Sep 27 '16 at 08:07
  • I believe this is the more elegant way of doing this. – Bnrdo Jun 27 '19 at 02:21

8 Answers8

33

I use a "blind" rethrow to pass up checked exceptions. I have used this for passing through the Streams API where I can't use lambdas which throw checked exceptions. e.g We have ThrowingXxxxx functional interfaces so the checked exception can be passed through.

This allows me to catch the checked exception in a caller naturally without needing to know a callee had to pass it through an interface which didn't allow checked exceptions.

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
  throw rethrow(e);
}

In a calling method I can declare the checked exception again.

public void loadFile(String file) throws IOException {
   // call method with rethrow
}

/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T>       the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

There is a lot of different options for handling exceptions. We use a few of them.

https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 2
    So this actually throws the IOException (from `rethrow`) at runtime but the compiler thinks that it's a unchecked exception (because you said you would cast it that way, even though the cast was erased)? – Thilo Sep 27 '16 at 08:16
  • 2
    @Thilo At runtime, there is no difference between checked and unchecked for the JVM and there is a few ways to "fool" the compiler which work at runtime. The cast using generics is the simplest I feel. – Peter Lawrey Sep 27 '16 at 08:18
  • 1
    Sneaky. I like it. :-) (and yes, not having exceptions from lamdbas is inconvenient). – Thilo Sep 27 '16 at 08:19
  • 9
    "Sneaky" is the semi-official name for this :) – Marko Topolnik Sep 27 '16 at 08:20
  • @MarkoTopolnik the polite name for it. There is also a word which rhythms with tack. ;) – Peter Lawrey Sep 27 '16 at 08:25
  • 1
    Succeeds in Java 8 but not in Java 7. Getting `Unhandled exception: java.lang.Throwable` in Java 7. Am I missing here something? – AlikElzin-kilaka Sep 27 '16 at 10:25
  • 5
    @AlikElzin-kilaka Yes, this syntax works only with the new inference rules in Java 8. A longer idiom with two methods is needed for Java 7. – Marko Topolnik Sep 27 '16 at 12:31
  • @AlikElzin-kilaka in java 7 you can do Thread.currentThread ().stop (e); – Peter Lawrey Sep 27 '16 at 12:41
  • But that would break forward compatibility since `stop()` has been discontinued and as of Java 8 it just throws an `UnsupportedOperationException`. – Marko Topolnik Sep 27 '16 at 12:45
  • @MarkoTopolnik indeed. We only use Java 8 so it hasn't been a problem. – Peter Lawrey Sep 27 '16 at 12:53
  • Why the compiler doesn't complaint about the `throws T`? Shouldn't it deduce that `T` is a `Throwable`? – Margaret Bloom Sep 27 '16 at 15:05
  • @MargaretBloom good question. It doesn't know if T is checked or not but allows it. Note Throwable is checked normally. – Peter Lawrey Sep 27 '16 at 15:43
  • @MargaretBloom There's a [special ruling](https://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html#jls-18.4) introduced in the Java 8 specification. – Marko Topolnik Sep 27 '16 at 15:54
  • What do you do at the catch site? If you just write `catch (IOException e)` and none of the code in the `try` block can throw checked exceptions, it will contain that the code in the `catch` block is unreachable, right? – Tavian Barnes Sep 27 '16 at 15:55
  • @TavianBarnes if it is thrown inside a method which `throws` the checked exception you can catch it outside the method call. – Peter Lawrey Sep 27 '16 at 16:08
  • @TavianBarnes worst case you have to write `if (false) throw new CheckedException();` however wrapping the code in a method makes it clearer imho. – Peter Lawrey Sep 27 '16 at 16:10
  • 1
    @PeterLawrey `throw rethrow(e);` why the extra `throw`? in bytecode however it will be ATHROW replaced with POP if remove the `throw`, so same size. – Mikhail Boyarsky May 12 '17 at 15:09
  • @MikhailBoyarsky its to make it clearer that something will be throw rather than a simple method call. – Peter Lawrey May 13 '17 at 21:58
20

Guava's Throwables.propagate() does exactly this:

try {
    // some code that can throw both checked and runtime exception
} catch (Exception e) {
    throw Throwables.propagate(e);
}

UPDATE: This method is now deprecated. See this page for a detailed explanation.

shmosel
  • 49,289
  • 6
  • 73
  • 138
  • Unrelated: today I (hope to) get to legendary gold ... just saying thanks to all the folks I learned so much from ... – GhostCat Sep 07 '17 at 06:49
4

Not really.

If you do this a lot, you could tuck it away into a helper method.

static RuntimeException unchecked(Throwable t){
    if (t instanceof RuntimeException){
      return (RuntimeException) t;
    } else if (t instanceof Error) { // if you don't want to wrap those
      throw (Error) t;
    } else {
      return new RuntimeException(t);
    }
}

try{
 // ..
}
catch (Exception e){
   throw unchecked(e);
}
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • change `catch (Exception e)` to `catch (Throwable e)` ? – Jason S Sep 27 '16 at 17:19
  • @JasonS: You could, if you also want to catch `Error` (which is not recommended). I'd just let those go uncaught. The compiler won't complain about it. – Thilo Sep 27 '16 at 23:30
  • I think the point was there's no reason to use `Throwable` and have a special case for `Error` if you're only catching `Exception`. – OrangeDog Sep 30 '16 at 21:09
  • @OrangeDog probably too much low-coupling, yeah. The method is more broadly applicable than the example calling code needs it to be. But that's the same for many of the exception-handling utilities, for example the already mentioned Guava `Throwables.propagate` or Peter's `rethrow`. – Thilo Sep 30 '16 at 23:14
2

I have a specially compiled .class file containing the following:

public class Thrower {
    public static void Throw(java.lang.Throwable t) {
        throw t;
    }
}

It just works. The java compiler would normally refuse to compile this, but the bytecode verifier doesn't care at all.

The class is used similar to Peter Lawrey's answer:

try {
  // some code that can throw both checked and runtime exception

} catch (Exception e) {
    Thrower.Throw(e);
}
Joshua
  • 40,822
  • 8
  • 72
  • 132
  • 5
    How did you compile it? – shmosel Sep 27 '16 at 17:01
  • 2
    I edited the javac source code to knock the check out, compiled javac, and used that javac to compile the .class file. The resulting .class file can be referenced by .java compiles compiled by the normal javac. – Joshua Sep 27 '16 at 17:23
  • Wow, not what I was expecting. Is the file available somewhere? – shmosel Sep 27 '16 at 17:26
  • Here's the instructions. I'm not sure but I think the blog poster got them from my original instructions on sun's old java bug repository. http://blog.bangbits.com/2009/08/tweaking-javac-leniency.html If the bug repository still exists, the .class file is there. – Joshua Sep 27 '16 at 17:29
  • 1
    Even sneakier than Peter's answer. I like it. – Thilo Sep 30 '16 at 23:15
1

You can rewrite the same using instanceof operator

try {
    // some code that can throw both checked and runtime exception
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        throw e;
    } else {
        throw new RuntimeException(e);
    }
}

However, your solution looks better.

Tionio
  • 79
  • 3
1

The problem is that Exception is too broad. You should know exactly what the possible checked exceptions are.

try {
    // code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
    throw new RuntimeException(ex);
}

The reasons why this wouldn't work reveal deeper problems that should be addressed instead:

If a method declares that it throws Exception then it is being too broad. Knowing that "something can go wrong" with no further information is of no use to a caller. The method should be using specific exception classes in a meaningful hierarchy, or using unchecked exceptions if appropriate.

If a method throws too many different kinds of checked exception then it is too complicated. It should either be refactored into multiple simpler methods, or the exceptions should be arranged in a sensible inheritance hierarchy, depending on the situation.

Of course there can be exceptions to the rule. Declaring a method throws Exception can be perfectly reasonable if it's consumed by some kind of cross-cutting framework (such as JUnit or AspectJ or Spring) rather than comprising an API for others to use.

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • 1
    His method is not declaring that it throws Exception, he's wanting to elegantly catch if something further down the call stack throws an exception, which could include any typed exception declared by the methods he directly calls, or anything else like a NPE or whatever that may go wrong. Perfectly reasonable. – user467257 Sep 27 '16 at 20:30
  • @user467257 yes I understand the OP. I'm pointing out that my suggested pattern won't work if the `try`d code is a method that `throws Exception`, but that's indicative of that method being poorly designed. – OrangeDog Sep 27 '16 at 20:32
1

I generally use the same type of code structure, but condense it down to one line in one of the few times a ternary operator actually makes code better:

try {
  // code that can throw
}
catch (Exception e) {
  throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}

This does not require additional methods or catch blocks which is why I like it.

0

lombok has this handled with a simple annotation on the method

Example:

import lombok.SneakyThrows;

@SneakyThrows
void methodThatUsusallyNeedsToDeclareException() {
    new FileInputStream("/doesn'tMatter");
}

In the example the method should have declared throws FileNotFoundException, but with the @SneakyThrows annotation, it doesn't.

What actually happens behind the scenes is that lombok does the same trick as the high rated answer to this same question.

Mission accomplished!

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277