NoException - Exception handlers for Java

NoException is functional programming for Java exception handlers. Many applications contain thousands of try-catch constructs and it's a mess. Catch clauses are verbose, repetitive, inconsistent, buggy, and hard to test. NoException provides a set of predefined exception handlers (try-catch replacements) that are concise and neat. You can define your own reusable handlers to fit policies of your project.

Example:

System.out.println(
    Exceptions.silence().get(() -> "test".substring(5)).orElse("fallback"));

The above is equivalent to the following try-catch code:

String result;
try {
    result = "test".substring(5);
} catch (Throwable exception) {
    result = "fallback";
}
System.out.println(result);

There's more to NoException. Read on.

Download

Get NoException from Maven Central:

Tool
<dependency>
    <groupId>com.machinezoo.noexception</groupId>
    <artifactId>noexception</artifactId>
    <version>1.9.1</version>
</dependency>

Or clone sources from GitHub or Bitbucket. Don't forget to configure your build for Java 11+. Last version compatible with Java 8 was 1.6.2. Sources and binaries are distributed under Apache License 2.0.

If your project is a Java module, add the following declaration to your module-info.java:

requires com.machinezoo.noexception;

Why?

Application code is often littered with boilerplate try-catch blocks. Verbosity of try-catch encourages developers to avoid it and to propagate exceptions instead. Notable recurring examples include fallbacks, callbacks, event/job loops, executors, and lambdas.

// Fallbacks: Exception severity escalated where log & fallback would suffice.
important.add(unimportant());

// Callbacks: Exception erroneously propagated to unrelated code.
if (callback != null)
    callback.run();

// Event/job loops: Exception kills the whole loop including unrelated jobs.
for (Job job : jobs)
    job.run();

// Executors: Exception lost in Future that is not awaited.
executor.submit(() -> Files.write("file", data));

// Lambdas: Compiler error due to checked exception.
process(() -> Files.readAllLines(path));

Tutorial

NoException defines a set of reusable checked and unchecked exception handlers (or exception blocks) and lets you easily define your own. NoException's handlers are concise, lambda-friendly, and thoroughly tested. They can be used to ensure correct and consistent exception handling throughout your project.

Catch-all handlers

If you just want to get rid of all exceptions, use Exceptions.silence().

String test = null;
Exceptions.silence().run(() -> System.out.println("This is a " + test));

If exception is thrown, Exceptions.silence() will catch it, discard it, and then it will return normally.

Fallbacks

To return a value, call get(Supplier) instead of run(Runnable). It returns standard Optional, which lets you specify fallback value via orElse(T) or fallback supplier via orElseGet(Supplier).

System.out.println(
    Exceptions.silence().get(() -> "test".substring(5)).orElse("fallback"));

Pass-through handlers

If you prefer the handler to rethrow the exception after processing it, you can call passing() method on the handler to get a pass-through version of the same exception handler.

for (String item : List.of("three", "two", "one")) {
    System.out.println(ExceptionLogging
        .log("Failed: " + item)
        .passing()
        .get(() -> item.substring(4))));
}

Notice there's no need for fallback value here.

Checked exceptions

You can avoid checked exception nuisance, especially on lambdas, by either wrapping checked exceptions in unchecked ones using Exceptions.wrap() or by sneaking them past compiler checks using Exceptions.sneak(), which will run some perfectly legal java code that tricks the compiler to let an undeclared checked exception through.

byte[] utf = Exceptions.sneak().get(() -> "test".getBytes("UTF-8"));

The above code can still throw checked exceptions, but the compiler believes it will not.

If you want to also catch the checked exceptions, combine checked and unchecked exception handlers:

static final List<String> lines = Exceptions.silence()
    .get(Exceptions.sneak().supplier(() -> Files.readAllLines("test.txt")))
    .orElse(Collections.emptyList());

Functional interfaces

To handle exceptions from functional interfaces with parameters, first wrap the functional interface and then apply its parameters.

Function<String, String> hello = x -> "Hello " + x;
System.out.println(Exceptions.silence().function(hello).apply(null).orElse("Who?"));

Method function(Function) above returns OptionalFunction, a special functional interface defined by NoException that returns Optional when executed. In order to pass it to a method that expects standard Function, you can call orElse(R) method on the OptionalFunction.

Function<Object, String> format = x -> "[" + x.toString() + "]";
Function<Object, String> safe = Exceptions.silence().function(format).orElse("???");
System.out.println(safe.apply(null));

Predefined handlers

Class Exceptions provides several predefined exception handlers:

Class ExceptionLogging from SLF4J extension provides additional logging handlers:

See current extension list for complete offering of predefined exception handlers.

Custom handlers

To create custom exception handler, override handle(Throwable) method of ExceptionHandler.

public class ExceptionCounter extends ExceptionHandler {
    private long count;
    @Override
    public synchronized boolean handle(Throwable exception) {
        ++count;
        return true;
    }
    public synchronized long report() {
        return count;
    }
}
public class ExceptionPolicy {
    private static final ExceptionCounter counter = new ExceptionCounter();
    public static ExceptionCounter count() {
        return counter;
    }
}

And use it anywhere:

ExceptionPolicy.count().run(() -> oftenFailingCode());
System.out.println(ExceptionPolicy.count().report());

A pass-through version can be derived by calling passing() or you can directly implement ExceptionFilter.

You can also define custom checked exception policy by implementing CheckedExceptionHandler, but you are usually better off supplying custom wrapper to wrap(Function<Exception,​ RuntimeException>).

public class ExceptionPolicy {
    public static CheckedExceptionHandler wrap(String message) {
        return Exceptions.wrap(e -> new RuntimeException(message, e));
    }
}

// example usage
ExceptionPolicy.wrap("Failed to save").run(() -> Files.write(path, data));

Configurator

You would normally use your IDE's auto-complete. This configurator is here only to help you understand the API. It shows canonical, idiomatic code.

Unchecked exceptions
Checked exceptions
Signature
Return
Then
String result = Exceptions.silence().get(() -> /* ... */).orElse("fallback");

// multi-line example
String result = Exceptions.silence().get(() -> {
    // ...
    return "result";
}).orElse("fallback");

See Exceptions.silence(), ExceptionHandler.get(Supplier).

Supported functional interfaces

NoException supports all standard functional interfaces in Java. The following table links to javadoc for every combination of functional interface and implemented feature. Link is missing only where it does not make sense, for example when the functional interface returns void or it is not parameterless.

Throwing interface
e.g. ThrowingRunnable
Optional interface
e.g. OptionalSupplier
Catch-all wrapper
e.g. runnable(Runnable)
Catch-all runner
e.g. run(Runnable)
Checked exception wrapper
e.g. runnable(ThrowingRunnable)
Checked exception runner
e.g. run(ThrowingRunnable)
Runnable
void run()
ThrowingRunnableExceptionHandler.runnable(Runnable)ExceptionHandler.run(Runnable)CheckedExceptionHandler.runnable(ThrowingRunnable)CheckedExceptionHandler.run(ThrowingRunnable)
Supplier
T get()
ThrowingSupplierOptionalSupplierExceptionHandler.supplier(Supplier)ExceptionHandler.get(Supplier)CheckedExceptionHandler.supplier(ThrowingSupplier)CheckedExceptionHandler.get(ThrowingSupplier)
IntSupplier
int getAsInt()
ThrowingIntSupplierOptionalIntSupplierExceptionHandler.fromIntSupplier(IntSupplier)ExceptionHandler.getAsInt(IntSupplier)CheckedExceptionHandler.fromIntSupplier(ThrowingIntSupplier)CheckedExceptionHandler.getAsInt(ThrowingIntSupplier)
LongSupplier
long getAsLong()
ThrowingLongSupplierOptionalLongSupplierExceptionHandler.fromLongSupplier(LongSupplier)ExceptionHandler.getAsLong(LongSupplier)CheckedExceptionHandler.fromLongSupplier(ThrowingLongSupplier)CheckedExceptionHandler.getAsLong(ThrowingLongSupplier)
DoubleSupplier
double getAsDouble()
ThrowingDoubleSupplierOptionalDoubleSupplierExceptionHandler.fromDoubleSupplier(DoubleSupplier)ExceptionHandler.getAsDouble(DoubleSupplier)CheckedExceptionHandler.fromDoubleSupplier(ThrowingDoubleSupplier)CheckedExceptionHandler.getAsDouble(ThrowingDoubleSupplier)
BooleanSupplier
boolean getAsBoolean()
ThrowingBooleanSupplierOptionalBooleanSupplierExceptionHandler.fromBooleanSupplier(BooleanSupplier)ExceptionHandler.getAsBoolean(BooleanSupplier)CheckedExceptionHandler.fromBooleanSupplier(ThrowingBooleanSupplier)CheckedExceptionHandler.getAsBoolean(ThrowingBooleanSupplier)
Predicate
boolean test(T t)
ThrowingPredicateOptionalPredicateExceptionHandler.predicate(Predicate)CheckedExceptionHandler.predicate(ThrowingPredicate)
IntPredicate
boolean test(int v)
ThrowingIntPredicateOptionalIntPredicateExceptionHandler.fromIntPredicate(IntPredicate)CheckedExceptionHandler.fromIntPredicate(ThrowingIntPredicate)
LongPredicate
boolean test(long v)
ThrowingLongPredicateOptionalLongPredicateExceptionHandler.fromLongPredicate(LongPredicate)CheckedExceptionHandler.fromLongPredicate(ThrowingLongPredicate)
DoublePredicate
boolean test(double v)
ThrowingDoublePredicateOptionalDoublePredicateExceptionHandler.fromDoublePredicate(DoublePredicate)CheckedExceptionHandler.fromDoublePredicate(ThrowingDoublePredicate)
Consumer
void accept(T t)
ThrowingConsumerExceptionHandler.consumer(Consumer)CheckedExceptionHandler.consumer(ThrowingConsumer)
IntConsumer
void accept(int v)
ThrowingIntConsumerExceptionHandler.fromIntConsumer(IntConsumer)CheckedExceptionHandler.fromIntConsumer(ThrowingIntConsumer)
LongConsumer
void accept(long v)
ThrowingLongConsumerExceptionHandler.fromLongConsumer(LongConsumer)CheckedExceptionHandler.fromLongConsumer(ThrowingLongConsumer)
DoubleConsumer
void accept(double v)
ThrowingDoubleConsumerExceptionHandler.fromDoubleConsumer(DoubleConsumer)CheckedExceptionHandler.fromDoubleConsumer(ThrowingDoubleConsumer)
BiConsumer
void accept(T t, U u)
ThrowingBiConsumerExceptionHandler.fromBiConsumer(BiConsumer)CheckedExceptionHandler.fromBiConsumer(ThrowingBiConsumer)
ObjIntConsumer
void accept(T t, int v)
ThrowingObjIntConsumerExceptionHandler.fromObjIntConsumer(ObjIntConsumer)CheckedExceptionHandler.fromObjIntConsumer(ThrowingObjIntConsumer)
ObjLongConsumer
void accept(T t, long v)
ThrowingObjLongConsumerExceptionHandler.fromObjLongConsumer(ObjLongConsumer)CheckedExceptionHandler.fromObjLongConsumer(ThrowingObjLongConsumer)
ObjDoubleConsumer
void accept(T t, double v)
ThrowingObjDoubleConsumerExceptionHandler.fromObjDoubleConsumer(ObjDoubleConsumer)CheckedExceptionHandler.fromObjDoubleConsumer(ThrowingObjDoubleConsumer)
UnaryOperator
T apply(T t)
ThrowingUnaryOperatorOptionalUnaryOperatorExceptionHandler.fromUnaryOperator(UnaryOperator)CheckedExceptionHandler.fromUnaryOperator(ThrowingUnaryOperator)
IntUnaryOperator
int applyAsInt(int v)
ThrowingIntUnaryOperatorOptionalIntUnaryOperatorExceptionHandler.fromIntUnaryOperator(IntUnaryOperator)CheckedExceptionHandler.fromIntUnaryOperator(ThrowingIntUnaryOperator)
LongUnaryOperator
long applyAsLong(long v)
ThrowingLongUnaryOperatorOptionalLongUnaryOperatorExceptionHandler.fromLongUnaryOperator(LongUnaryOperator)CheckedExceptionHandler.fromLongUnaryOperator(ThrowingLongUnaryOperator)
DoubleUnaryOperator
double applyAsDouble(double v)
ThrowingDoubleUnaryOperatorOptionalDoubleUnaryOperatorExceptionHandler.fromDoubleUnaryOperator(DoubleUnaryOperator)CheckedExceptionHandler.fromDoubleUnaryOperator(ThrowingDoubleUnaryOperator)
BinaryOperator
T apply(T l, R r)
ThrowingBinaryOperatorOptionalBinaryOperatorExceptionHandler.fromBinaryOperator(BinaryOperator)CheckedExceptionHandler.fromBinaryOperator(ThrowingBinaryOperator)
IntBinaryOperator
int applyAsInt(int l, int r)
ThrowingIntBinaryOperatorOptionalIntBinaryOperatorExceptionHandler.fromIntBinaryOperator(IntBinaryOperator)CheckedExceptionHandler.fromIntBinaryOperator(ThrowingIntBinaryOperator)
LongBinaryOperator
long applyAsLong(long l, long r)
ThrowingLongBinaryOperatorOptionalLongBinaryOperatorExceptionHandler.fromLongBinaryOperator(LongBinaryOperator)CheckedExceptionHandler.fromLongBinaryOperator(ThrowingLongBinaryOperator)
DoubleBinaryOperator
double applyAsDouble(double l, double r)
ThrowingDoubleBinaryOperatorOptionalDoubleBinaryOperatorExceptionHandler.fromDoubleBinaryOperator(DoubleBinaryOperator)CheckedExceptionHandler.fromDoubleBinaryOperator(ThrowingDoubleBinaryOperator)
Function
R apply(T t)
ThrowingFunctionOptionalFunctionExceptionHandler.function(Function)CheckedExceptionHandler.function(ThrowingFunction)
IntFunction
R apply(int v)
ThrowingIntFunctionOptionalIntFunctionExceptionHandler.fromIntFunction(IntFunction)CheckedExceptionHandler.fromIntFunction(ThrowingIntFunction)
LongFunction
R apply(long v)
ThrowingLongFunctionOptionalLongFunctionExceptionHandler.fromLongFunction(LongFunction)CheckedExceptionHandler.fromLongFunction(ThrowingLongFunction)
DoubleFunction
R apply(double v)
ThrowingDoubleFunctionOptionalDoubleFunctionExceptionHandler.fromDoubleFunction(DoubleFunction)CheckedExceptionHandler.fromDoubleFunction(ThrowingDoubleFunction)
ToIntFunction
int applyAsInt(T t)
ThrowingToIntFunctionOptionalToIntFunctionExceptionHandler.fromToIntFunction(ToIntFunction)CheckedExceptionHandler.fromToIntFunction(ThrowingToIntFunction)
ToLongFunction
long applyAsLong(T t)
ThrowingToLongFunctionOptionalToLongFunctionExceptionHandler.fromToLongFunction(ToLongFunction)CheckedExceptionHandler.fromToLongFunction(ThrowingToLongFunction)
ToDoubleFunction
double applyAsDouble(T t)
ThrowingToDoubleFunctionOptionalToDoubleFunctionExceptionHandler.fromToDoubleFunction(ToDoubleFunction)CheckedExceptionHandler.fromToDoubleFunction(ThrowingToDoubleFunction)
IntToLongFunction
long applyAsLong(int v)
ThrowingIntToLongFunctionOptionalIntToLongFunctionExceptionHandler.fromIntToLongFunction(IntToLongFunction)CheckedExceptionHandler.fromIntToLongFunction(ThrowingIntToLongFunction)
IntToDoubleFunction
double applyAsDouble(int v)
ThrowingIntToDoubleFunctionOptionalIntToDoubleFunctionExceptionHandler.fromIntToDoubleFunction(IntToDoubleFunction)CheckedExceptionHandler.fromIntToDoubleFunction(ThrowingIntToDoubleFunction)
LongToIntFunction
int applyAsInt(long v)
ThrowingLongToIntFunctionOptionalLongToIntFunctionExceptionHandler.fromLongToIntFunction(LongToIntFunction)CheckedExceptionHandler.fromLongToIntFunction(ThrowingLongToIntFunction)
LongToDoubleFunction
double applyAsDouble(long v)
ThrowingLongToDoubleFunctionOptionalLongToDoubleFunctionExceptionHandler.fromLongToDoubleFunction(LongToDoubleFunction)CheckedExceptionHandler.fromLongToDoubleFunction(ThrowingLongToDoubleFunction)
DoubleToIntFunction
int applyAsInt(double v)
ThrowingDoubleToIntFunctionOptionalDoubleToIntFunctionExceptionHandler.fromDoubleToIntFunction(DoubleToIntFunction)CheckedExceptionHandler.fromDoubleToIntFunction(ThrowingDoubleToIntFunction)
DoubleToLongFunction
long applyAsLong(double v)
ThrowingDoubleToLongFunctionOptionalDoubleToLongFunctionExceptionHandler.fromDoubleToLongFunction(DoubleToLongFunction)CheckedExceptionHandler.fromDoubleToLongFunction(ThrowingDoubleToLongFunction)
BiFunction
R apply(T t, U u)
ThrowingBiFunctionOptionalBiFunctionExceptionHandler.fromBiFunction(BiFunction)CheckedExceptionHandler.fromBiFunction(ThrowingBiFunction)
ToIntBiFunction
int applyAsInt(T t, U u)
ThrowingToIntBiFunctionOptionalToIntBiFunctionExceptionHandler.fromToIntBiFunction(ToIntBiFunction)CheckedExceptionHandler.fromToIntBiFunction(ThrowingToIntBiFunction)
ToLongBiFunction
long applyAsLong(T t, U u)
ThrowingToLongBiFunctionOptionalToLongBiFunctionExceptionHandler.fromToLongBiFunction(ToLongBiFunction)CheckedExceptionHandler.fromToLongBiFunction(ThrowingToLongBiFunction)
ToDoubleBiFunction
double applyAsDouble(T t, U u)
ThrowingToDoubleBiFunctionOptionalToDoubleBiFunctionExceptionHandler.fromToDoubleBiFunction(ToDoubleBiFunction)CheckedExceptionHandler.fromToDoubleBiFunction(ThrowingToDoubleBiFunction)
Comparator
int compare(T l, T r)
ThrowingComparatorOptionalComparatorExceptionHandler.comparator(Comparator)CheckedExceptionHandler.comparator(ThrowingComparator)
CloseableScope
void close()
AutoCloseableExceptionHandler.closeable(CloseableScope)CheckedExceptionHandler.closeable(ThrowingCloseableScope)

Alternatives

NoException was developed shortly after Java 8 launch, but I kept it as an internal project. By the time I got around to publishing it, there were several other projects solving the same problem. I am nevertheless pleasantly surprised that NoException is a clean superset of functionality in the other projects.

NoException fge jOOL StreamUnthrower Liebenberg Durian Faux Pas
Logging handler yes no no no rethrowing yes no
Silent handler yes no no no yes yes no
Custom handler yes no yes no yes yes no
Wrapped rethrow yes yes yes no no yes no
Sneaky rethrow yes yes yes yes yes no yes
Wraps lambda yes yes yes no yes yes yes
Runs lambda yes no no yes no yes no
Optional return yes custom no no no fallback only no
Supported interfaces all all all custom all few some
Tutorial yes yes yes yes yes sort of yes
Javadoc yes no yes no yes yes no
Maven Central yes yes yes no yes yes yes
Feature comparison of exception handling libraries

Next steps