Skip to content
Francis Galiegue edited this page Mar 5, 2015 · 11 revisions

The basics

Short recall: a lambda can be...

Several things:

  • a hand written lambda: (list, of, arguments) -> { /* code of the lambda here };
  • a method reference (and there are a lot of possibilities; see here);
  • an instance of a class implementing the expected functional interface;
  • etc etc.

The interfaces

When you declare a ThrowingFoo version of an interface Foo as in:

final ThrowingFunction<Input, Output> function = someLambdaHere;

this variable is directly usable as a Foo, since all ThrowingFoo interfaces extend their Foo counterparts.

The default behavior, which you can alter, is that if a checked exception is thrown, it is wrapped into a ThrownByLambdaException.

You can, if you wish to, capture that exception and see the cause of the failure (using .getCause()).

All unchecked exceptions (ie, RuntimeExceptions) and Errors are thrown as is.

The wrappers

For each functional interface covered by this package, there is an equivalent method in the Throwing class which will return an instance of a Chainer. For instance:

  • Throwing.function(...);
  • Throwing.intConsumer(...);
  • Throwing.longBinaryOperator(...);
  • etc etc.

Customizing the behavior

Customization common to all interfaces

You can customize the behavior of an interface in three ways:

  • throw a different exception than the default: .orThrow();
  • try with a different, throwable lambda: .orTryWith();
  • fallback to a non throwable lambda of the same version: .fallbackTo().

Note: .orTryWith() is chainable, which means you can try with other throwing lambdas etc etc.

Examples:

Throwing.biFunction(my::method).orThrow(MyException.class);
Throwing.consumer(my -> { lambda(); here(); }).fallbackTo(nonThrowing -> { lambda(); here(); });
Throwing.intSupplier(first::lambda).orTrywith(other::lambda).fallbackTo(last::resort);
Throwing.doubleBinaryOperator(first::lambda).orTryWith(other::lambda).orThrow(MyException.class);

Specific customizations

Depending on the type of throwing interface you have, you also have specific customizations available:

  • all interfaces and their primitive versions except for Consumers: .orReturn(someValue);
  • Consumers: .orDoNothing();
  • UnaryOperators: .orReturnSelf();
  • BinaryOperators: .orReturnLeft(), .orReturnRight().

Taking the example of Path::toRealPath, here is how you would tell, in a stream, to return the argument itself if the method fails with an exception:

// Due to a limit in type inference, you have to declare this:
final FunctionChainer<Path, Path> chainer = Throwing.unaryOperator(Path::toRealPath);
// It is important to use Operators and not Functions here!
Files.list(someDir).map(chainer.orReturnSelf())