This change tackles the problem of having checked exceptions in Java.
import java.util.stream.Stream;
// <ceremony omitted>
// not possible with Java this way
Stream.of("java.lang.Object").map(MyType::methodThatThrows);
Current solutions
java
.map(v -> {
try {
return methodThatThrows(v);
} catch (Exception x) {
throw new RuntimeException(x);
}
})
java
.map(CheckedFunction1.<U, V> of(MyType::methodThatThrows).unchecked())
java
.map(v -> Try.of(() -> methodThatThrows(v)))
In 2010, Brian Goetz wrote:

(Source: Exception transparency)
Back to that time Brian proposed to make exceptions transparent (and solve this issue) by adding a throws clause to generic type parameters:

I don't know if this proposal will ever make it into the Java language.
We want to remove CheckedFunction0..8 in favor of enhancing our existing Function0..8 with checked exception functionality.
Function0<R> extends Supplier<R>Function1<T1, R> extends Function<T1, R>Function2<T1, T2, R> extends BiFunction<T1, T2, R>These additionally get a throwing method
call(...) throws Throwable
The existing, non-throwing method apply(...) will delegate to call() and _sneaky throw_. This will _emulate_ unchecked exceptions in Java.
Because users and libraries already wrap exceptions in RuntimeExceptions, it can't be considered as unsafe per se. However, we aren't able to make it explicit, which excetions will be thrown at runtime. That's the way, unchecked exceptions work.
// may throw an unchecked exception when a Function1 is passed as argument
<T, U, R> R fun(Function<T, U> f);
// must not throw, even if a Function1 is passed as argument
<T, U, R> Try<R> fun(Function<T, U> f);
// map(Function1<T, R> f)
.map(MyType::methodThatThrows);
// map(Function<T, R> f)
// Function1<T, R> f = MyType::methodThatThrows;
.map(f);
// map(Function<T, R> f)
.map(Function1.of(MyType::methodThatThrows));
@FunctionalInterface
interface Function1<T1, R> extends Serializable, Function<T1, R> {
static <T1, R> Function1<T1, R> of(Function1<T1, R> f) {
return f;
}
R call(T1 t1) throws Throwable;
default R apply(T1 t1) {
try {
return call(t1);
} catch(Throwable x) {
return sneakyThrow(x);
}
}
default <V> Function1<V, R> compose(Function<? super V, ? extends T1> before) {
Objects.requireNonNull(before);
return (V v) -> call(before.apply(v));
}
default <V> Function1<T1, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T1 t1) -> after.apply(call(t1));
}
static <T> Function1<T, T> identity() {
return t -> t;
}
}
// put this in a safe place, don't expose it as part of the public API
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
We will solve this issue in VAVR 1.0.0 and mark CheckedFunction0..8 as deprecated (to be removed in 2.0.0).
Update: Since someone asked, yes, the stack trace reflects all places where a sneaky exception occurred.
The only problem with the sneaky throws approach is that, you won't be able to catch a _specific_ checked exception when it gets hidden like this, because the compiler will think a specific checked exception is not thrown since it's not declared. One would have to catch the broader Exception type.

I'm not sure which approach would be better: the sneaky throws one, or selectively wrapping checked exceptions in a runtime exception and rethrowing those that are already unchecked. With the latter way, at least one could choose to catch only the wrapper exception and not other exception type which might be uninteresting for him.
The presence of the above compiler error is frustrating in itself because it presents the programmer with a strange situation when he knows that there might be a checked exception thrown but he's not able to catch it, because the compiler doesn't allow him to do so. Wrapping checked exceptions in an unchecked wrapper runtime exception is the usual thing that most libraries do when handling similar situations, so it might be more familiar with the users.
The presence of the above compiler error is frustrating in itself because it presents the programmer with a strange situation when he knows that there might be a checked exception thrown but he's not able to catch it, because the compiler doesn't allow him to do so
You follow wrong assumptions. If you refactor your code or exchange third party libs, it might be a different exception that is thrown. This is how unchecked exceptions work (in all other languages and simulated by sneaky throw in VAVR)!
Sneaky throwing is the right way because Java's idea of exceptions is broken. Today's Java programmers are already brainwashed. I talked to several developers who think that only Error and Exception exist.
But the real problem of Java is, that they leaked unchecked exceptions into their concept of checked exceptions, namely:
Error extends ThrowableRuntimeException extends ExceptionIn a safe production environment, you must catch (and probably log) both of these exception types. Their least common denominator is Throwable.

Because I know that the question will be raised, I will elaborate on catching Error. It is a wrong assumption, that exceptions of type Error are fatal. On the one hand, it is naive to think that all developers follow conventions. On the other hand an exception can be only considered fatal, if it prevents the JVM from going on executing the underlying application in a correct and deterministic way. StackOverflowError for example might be considered as non-fatal because the call stack is cleaned up.
This is, how your example needs to look like:
import java.io.Serializable;
import java.util.Objects;
import java.util.function.Function;
public class Delme {
static Object throwingFn(Object a) throws CheckedException {
throw new CheckedException();
}
static <T, R> R invoke(T a, Function1<T, R> fn) {
return fn.apply(a);
}
public static void main(String[] args) {
try {
invoke("", Delme::throwingFn);
} catch(Throwable x) {
//
// Log, check instanceof and whatever you decide needs to be done
// in order to make your application safe at (!) runtime (!)
//
// Relying on green lights by your IDE and the compiler is unsafe.
// Expect the unexpected at runtime!!!
//
}
}
}
class CheckedException extends Exception {
}
@FunctionalInterface
interface Function1<T1, R> extends Serializable, Function<T1, R> {
static <T1, R> Function1<T1, R> of(Function1<T1, R> f) {
return f;
}
R call(T1 t1) throws Throwable;
default R apply(T1 t1) {
try {
return call(t1);
} catch(Throwable x) {
return sneakyThrow(x);
}
}
default <V> Function1<V, R> compose(Function<? super V, ? extends T1> before) {
Objects.requireNonNull(before);
return (V v) -> call(before.apply(v));
}
default <V> Function1<T1, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T1 t1) -> after.apply(call(t1));
}
static <T> Function1<T, T> identity() {
return t -> t;
}
// put this in a safe place, don't expose it as part of the public API
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
I think we're talking past each other.
I was talking about those cases where you want to only catch the specific checked exception that is being hidden from the method signatures, and in a local context. Not general error-handling in a broad, app level context. But never mind, it doesn't really matter because we would still had to do instanceof checks to filter for the specific exception type that we're interested in handling, even if we chose to wrap checked exceptions in an unchecked wrapper.
This problem is caused by the Java compiler's wrong assumption, that if a checked exception is not declared to be thrown from a code block, it will NOT be thrown. That assumption is clearly wrong, as it's demonstrated by the sneaky throws trick. But now we have to work around this compiler limitation by catching a much broader exception type in local context, only to filter for the exception type we care about to handle it, and let the other exception type propagate.
Given an API Stream.map(Function) and the wish to use it with a throwing function, like Class::forName, we have the following options:
| | Sneaky Throw | Unchecked Exception | Checked Exception | _Description_ |
| --- | --- | --- | --- | --- |
| Conciseness | ✅concise | ✅concise | 🚫wrapping | _Reduces boilerplate_ |
| Integration | ✅works | ✅works | 🛑blocker1) | _Works with unchecked higher-order functions_ |
| Correctness | ✅correct | 🛑conflict2) | ✅correct | _Changing the exception type is changing original semantics_ |
| Familiarity | 🚫unfamiliar3) | ✅familiar | ✅familiar | _Java devs know how to use them_ |
| Safety | 🚫unsafe | 🚫unsafe | ✅safe | _Static type checking_ |
Ad 1): Our goal is to give our users the opportunity to use unchecked higher-order functions with checked exceptions. Currently it is unpopular (but best) practice, to manually wrap an exception in an unchecked exception (namely: RuntimeException or Error).
Ad 2): A big problem is that we are not able to decide whether or not a checked exception is an error or just an ordinary exception. I see this as a blocker for just wrapping any throwable in a runtime exception. In the _scope of this aspect_ only, it would be better to sneaky throw the original exception.
Ad 3): The main problem seems to be a mental one: Java users are not used to catch Throwable instead of RuntimeException. Sneaky throw does not introduce another safety problem. RuntimeExceptions are equally unsafe. I don't see the aspect of familiarity as a blocker.
The big benefit of _sneaky throw_ is that original exceptions are transported, exactly like it is the case with native language support for unchecked exceptions (in all other languages but Java).
interface Func<T, R> extends Function<T, R> {
R call(T t) throws Throwable;
default R apply(T t) {
try {
return call(t);
} catch(Throwable x) {
return sneakyThrow(x); // rethrows the original exception x
}
}
default <V> Func<V, R> compose(Function<? super V, ? extends T> before) {
return (V v) -> call(before.apply(v));
}
default <V> Func<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> after.apply(call(t));
}
}
However, as stated before, it is unfamiliar to developers and unsafe. The aspect of unfamiliarity could be fixed by wrapping checked exceptions in runtime exceptions:
interface Func<T, R> extends Function<T, R> {
R call(T t) throws Throwable;
default R apply(T t) {
try {
return call(t);
} catch (Error | RuntimeException x) {
throw x; // rethrow unchecked exceptions
} catch(Throwable x) {
// wrap checked exceptions in a runtime exception
throw new RuntimeException(x);
}
}
default <V> Func<V, R> compose(Function<? super V, ? extends T> before) {
return (V v) -> call(before.apply(v));
}
default <V> Func<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> after.apply(call(t));
}
}
Note: by rethrowing unchecked exceptions, we prevent building deep runtime exception cascades when composing functions using compose() and andThen().
Exception should be wrapped in a vavr specific WrappedException extends RuntimeException (plus cause, modulo better naming ;-)) to keep semantics. A dev would then still be able to distinguish between (sub class of) RuntimeException originally thrown by the code and re-thrown WrappedException.getCause. This would also keep vavr libraries from nesting these ever deeper.
(Edit: basically what @nfekete advocates)
@rkraneis exactly. We're hiding checked exceptions behind higher order functions. As these are not present in these function's method signatures, that makes it impossible to catch them because of the above compiler limitation. There are many cases where we would want to handle those exceptions in a narrow context close to where they happened, so there are two options:
Exception and do instanceof checks, selectively handle the exception you're interested in and rethrow all otherstry {}. The user doesn't have to catch a broad throwable type like Exception so usually there is no need to selectively rethrow. To me this seems to be a bit simpler than the sneaky throws one, without the confusing compiler error the user would get in case he tried to catch the specific checked exception.Catching a specific original runtime exception is the same for both cases.
@danieldietrich, do you still remember what your concrete objections to sneakyThrows where in #2049? Are they still relevant?
@rkraneis the situation changed. Sneaky throw is the future now. According to the actual JVM Summit, Oracle _seems to plan_ to remove checked exceptions. That would imply that sneaky throw is the way to go. It would be fully align to future unchecked exceptions in the JVM.

Better image that shows "Oracle":

That would be really nice. That's the JVMLS summit, right? It would be kind of natural to see an Oracle logo at this event. But is he authoritative on this issue? Care to elaborate, @forax? Is Oracle planning to remove checked exception from Java?
I'm missing a fourth column above: No use Try instead. CheckedFunctions should be reserved for use with Try. Making this a breeze to use would require to include my proposals for rethrowing or something similar. This is IMHO by far the best option.
I never use CheckedFunctions currently because they are declared to throw Throwable. This declaration breaks code, no one should ever catch(Throwable) (except in ultra-safe code that is only written by people who know very well what they're doing). Errors should normally not be caught except in very special situations (that's why they're unchecked and have their own class hierarchy), and if you catch them, you should know what you're doing. throws Throwable forces people to also catch Errors, so it forces an anti-pattern. Therefore, also CheckedFunctions should be declared throws Exception.
SneakyThrow is IMHO never an option because it's a compiler error if you try to catch sneakyThrown checked exceptions. OK, you could catch Throwable, but then we're back at the point above: catch(Throwable) is bad, very verbose and only for advanced Java programmers. SneakyThrow would kill Vavr for me, this is an absolute no-go, IMO.
I won't go into whether checked exceptions are good or not. Just this: I used to hate them until I found the concept of Try – with a proper Try (which Vavr currently doesn't provide, although the workaround is easy), they're just slightly annoying, I even started to like them somewhat.
But the important thing is: this is Java and in Java, checked exceptions are a reality. Working around them is working against one of Java's core concepts. Work with them instead. The more I accept checked exceptions and work with them, the less I hate them. Which leads us back to the beginning of my comment: use Try.
@nfekete,
don't trust twitter,
Oracle has no plan to remove checked exception.
@forax thanks for the input. I don't trust random images from twitter, and I was highly skeptical about the implication, but I could have been wrong too dismissing it outright as false without further information. That's why I tried to ask you directly and thanks again for the clarification.
Hi @Abnaxos and @nfekete,
thank you for your feedback. I've thought a while about it and now I think I was totally off the course. Sneaky throw would undermine safety to the max. It could blow up all applications that have VAVR as transitive dependency.
As long as Java does not officially drops checked exceptions (which will most probably never happen), we can't treat checked exceptions as unchecked exceptions. I understand your points.
@Abnaxos is right, "CheckedFunctions should be reserved for use with Try". That's also my opinion. Therefore I moved these functional interfaces on the current 2.0.0 branch to the control package, side-by-side with Try.
We should keep it that way. I will close this issue.
Again, thank you for your input. I really appreciate it if you pull me out of a neurologic cycle ;) 🌀
Most helpful comment
Hi @Abnaxos and @nfekete,
thank you for your feedback. I've thought a while about it and now I think I was totally off the course. Sneaky throw would undermine safety to the max. It could blow up all applications that have VAVR as transitive dependency.
As long as Java does not officially drops checked exceptions (which will most probably never happen), we can't treat checked exceptions as unchecked exceptions. I understand your points.
@Abnaxos is right, "CheckedFunctions should be reserved for use with Try". That's also my opinion. Therefore I moved these functional interfaces on the current 2.0.0 branch to the control package, side-by-side with Try.
We should keep it that way. I will close this issue.
Again, thank you for your input. I really appreciate it if you pull me out of a neurologic cycle ;) 🌀