Skip to content
fge edited this page Dec 27, 2014 · 8 revisions

New interfaces...

Credits where they are due: thanks to Vincentyfication for the design idea

For each functional interface Foo usable in Streams, this package defines an interface ThrowingFoo. For instance, here is the interface ThrowingFunction:

@FunctionalInterface
public interface ThrowingFunction<T, R>
    extends Function<T, R>
{
    R doApply(T t)
        throws Throwable;

    @Override
    default R apply(T t)
    {
        try {
            return doApply(t);
        } catch (Error | RuntimeException e) {
            throw e;
        } catch (Throwable tooBad) {
            throw new ThrownByLambdaException(tooBad);
        }
    }

    default Function<T, R> orReturn(R defaultValue)
    {
        return t -> {
            try {
                return doApply(t);
            } catch (Error | RuntimeException e) {
                throw e;
            } catch (Throwable ignored) {
                return defaultValue;
            }
        };
    }

    default <E extends RuntimeException> Function<T, R> orThrow(
        Class<E> exceptionClass)
    {
        return t -> {
            try {
                return doApply(t);
            } catch (Error | RuntimeException e) {
                throw e;
            } catch (Throwable tooBad) {
                throw ThrowablesFactory.INSTANCE.get(exceptionClass, tooBad);
            }
        };
    }
}

As you can see, all RuntimeExceptions and Errors are left untouched. Any other Throwable depends on what you use :

  • by default, they are wrapped into an unchecked ThrownByLambdaException, and the cause is set as this Throwable;
  • if you chain with .orThrow(SomeException.class) then this exception (which must also be unchecked) is thrown instead, and the cause is also set as the Throwable thrown by the lambda;
  • if you chain with .orReturn(someValue) then this value is returned instead.

All functional interfaces extended this way have .orThrow(); as to other chaining methods, they depend on the return types of their interface (Consumers have .orDoNothing() for instance, and Operators have .orReturnSelf() in addition to .orReturn()).

The wrappers

The wrapper methods are defined in a utility class and simply wraps a ThrowingFoo into a Foo. For Function, this is defined in class Functions:

// Old
public static <T, R> Function<T, R> rethrow(final ThrowingFunction<T, R> f)
{
    return f;
}

// New
public static <T, R> ThrowingFunction<T, R> wrap(final ThrowingFunction<T, R> f)
{
    return f;
}
Clone this wiki locally