Skip to content

Lambda Expressions and Exception Handling

This short article will explore a few options to handle checked and unchecked exceptions in lambda expressions.

Sumit Gaur
Sumit Gaur
3 min read
Lambda Expressions and Exception Handling
Photo by Kelly Sikkema / Unsplash

With the introduction of lambda expressions in Java8, significant support was added for functional-style programming, thus promoting a more concise coding style.

But even then, the lambda expressions lag basic exception handling features and at times lead to more verbose code on the contrary.

This short article will explore a few options to wrap lambda expressions inside exception handlers for checked and unchecked exceptions.

Exception Prone Action

The first task for us is to define an exception-prone action that can terminate abruptly due to a checked or unchecked exception. As we anyways have to devise a solution for lambda expressions, this action has to be a FunctionalInterface that we can use to map lambda expressions.

Depending on our requirement, we can have actions that map lambda expressions with or without a return value.

Action with return value

The following is an example of a FunctionalInterface, to which lambda expression - producing some results on completion, can map to:

@FunctionalInterface
public interface ExceptionProneAction<T> {
	T doAction() throws Exception;
}
ExceptionProneAction with return value

Here the generic type <T> refers to the result type that the lambda expression will produce after completion.

Action without return value

On similar lines, we can write another interface to which lambda expressions without a return value can map:

@FunctionalInterface
public interface ExceptionProneActionWithNoResult{
	void doAction() throws Exception;
}
ExceptionProneAction with NO return value

Utility Methods to wrap exceptions

Once our actions are ready, we need to write utility methods that accept lambda expressions (mapped to those actions) and trigger the corresponding operations. The idea is to re-use these actions and utility methods wherever we need to handle exceptions while working with lambda expressions:

Unchecked with no return value

The following method handles an action capable of throwing a checked exception. The exception can be either only logged or processed by a concrete exception handler passed as an argument:

public static void uncheckedNoReturnValue(final ExceptionProneActionWithNoResult action, Consumer<Exception> handler){
	try{
    	action.doAction();
    }catch(Exception exception){
    	if(null != handler){
        	handler.accept(exception);
        }
        logger.error("exception logged with some relevant message", exception);
    }
}
Wrapping exception prone action with no return value

To use the action and utility method, we can write a wrapped lambda expression as follows:

uncheckedNoReturnValue(() -> Files.copy(Paths.get("from_path"),
					Paths.get("to_path"), StandardCopyOption.REPLACE_EXISTING), null);
Example: wrap a lambda with no return value and no exception handler

Unchecked with return value

The only difference between the two versions is related to the underlying action to which lambda expression maps. For example, consider the following utility method that we can use to wrap lambda expressions with some return value:

public static <T> T void uncheckedWithReturnValue(final ExceptionProneAction<T> action, Consumer<Exception> handler){
	T results = null;
    try{
    	result = action.doAction();
    }catch(Exception exception){
    	if(null != handler){
        	handler.accept(exception);
        }
        logger.error("exception logged with some relevant message", exception);
    }
    return results;
}
Wrapping exception prone action with return value

The following snippet shows how we can use the utility method to wrap a lambda expression with a return value having the potential to throw an exception:

Integer result = uncheckedWithReturnValue(days -> Integer.parseInt(days), 
			 ex -> logger.error("this is a demo exception handler", ex));
Example: wrap a lambda with return value

Re-throwing exceptions

To further increase the available options, we can write additional utility methods that, instead of handling the exceptions themselves, throw those back to the calling code after wrapping the exceptions in some generic or application-specific exception that the client can handle.

The actions and utility methods mentioned above reduce the boilerplate code associated with traditional exception handling(via try-catch blocks). Moreover, it is now limited to only the static utility methods.  This way, we can write clean code which is more readable and is more aligned with the functional code style.  


That is all for this post. If you want to share any feedback, please drop me an email, or contact me on any social platforms. I’ll try to respond at the earliest. Also, please consider subscribing for regular updates.

Design ForumFeaturesHow To

Sumit Gaur

A passionate java developer and open source advocate, who understands the value of continuous learning and sharing knowledge.