Exception handling in Java 8 lambda expressions

Introduction to the

The introduction of lambda expressions in Java 8 makes our code simpler and business logic clearer, but the Functional Interface used in lambda expressions doesn’t handle exceptions very well. Because the Functional interfaces provided by the JDK generally do not throw exceptions, this means we need to handle exceptions manually.

Since exceptions are categorized as Unchecked and Unchecked exceptions, we’ll discuss them separately.

Processing of Unchecked Exception

An Unchecked Exception is also called a RuntimeException, and runtimeexceptions are generally caused by problems with our code. RuntimeException does not need to be caught. That is, if there is a RuntimeException, you can compile without capturing it.

Let’s look at an example:

List<Integer> integers = Arrays.asList(1.2.3.4.5);
        integers.forEach(i -> System.out.println(1 / i));
Copy the code

This example compiles successfully, but there is a problem with the ArithmeticException that is thrown if the list has a 0 in it.

While this is an Unchecked Exception, we’ll throw something like this:

        integers.forEach(i -> {
            try {
                System.out.println(1 / i);
            } catch (ArithmeticException e) {
                System.err.println(
                        "Arithmetic Exception occured : "+ e.getMessage()); }});Copy the code

The above example uses try and catch to handle exceptions, which is simple but breaks best practice for lambda expressions. The code becomes bloated.

We move the try, catch to a wrapper method:

    static Consumer<Integer> lambdaWrapper(Consumer<Integer> consumer) {
        return i -> {
            try {
                consumer.accept(i);
            } catch (ArithmeticException e) {
                System.err.println(
                        "Arithmetic Exception occured : "+ e.getMessage()); }}; }Copy the code

The original call looks like this:

integers.forEach(lambdaWrapper(i -> System.out.println(1 / i)));
Copy the code

But the wrapper above fixed the capture ArithmeticException, which we adapted into a more general class:

    static <T, E extends Exception> Consumer<T>
    consumerWrapperWithExceptionClass(Consumer<T> consumer, Class<E> clazz) {

        return i -> {
            try {
                consumer.accept(i);
            } catch (Exception ex) {
                try {
                    E exCast = clazz.cast(ex);
                    System.err.println(
                            "Exception occured : " + exCast.getMessage());
                } catch (ClassCastException ccEx) {
                    throwex; }}}; }Copy the code

The above class passes in a class and casts it to an exception, if it can be cast, and otherwise throws an exception.

After doing so, we call:

integers.forEach(
                consumerWrapperWithExceptionClass(
                        i -> System.out.println(1 / i),
                        ArithmeticException.class));
Copy the code

Handle checked Exception

Checked Exception is an Exception that must be handled, so let’s look at an example:

    static void throwIOException(Integer integer) throws IOException {}Copy the code
List<Integer> integers = Arrays.asList(1.2.3.4.5);
        integers.forEach(i -> throwIOException(i));
Copy the code

Above we defined a method to throw IOException, which is a Checked Exception that needs to be handled, so in the following forEach, the program will fail to compile because it did not handle the corresponding Exception.

The simplest way to do this is to try and catch, as follows:

        integers.forEach(i -> {
            try {
                throwIOException(i);
            } catch (IOException e) {
                throw newRuntimeException(e); }});Copy the code

Of course, the downside of doing this has already been covered above, and again we can define a new wrapper method:

    static <T> Consumer<T> consumerWrapper( ThrowingConsumer
       
         throwingConsumer)
       ,> {

        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw newRuntimeException(ex); }}; }Copy the code

We call it like this:

integers.forEach(consumerWrapper(i -> throwIOException(i)));
Copy the code

We can also encapsulate exceptions:

static <T, E extends Exception> Consumer<T> consumerWrapperWithExceptionClass( ThrowingConsumer
       
         throwingConsumer, Class
        
          exceptionClass)
        
       ,> {

        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                try {
                    E exCast = exceptionClass.cast(ex);
                    System.err.println(
                            "Exception occured : " + exCast.getMessage());
                } catch (ClassCastException ccEx) {
                    throw newRuntimeException(ex); }}}; }Copy the code

Then call it like this:

integers.forEach(consumerWrapperWithExceptionClass(
                i -> throwIOException(i), IOException.class));
Copy the code

conclusion

This article has provided you with an introduction to handling checked and unchecked exceptions in lambda expressions.

Examples of this article github.com/ddean2009/l…

Welcome to pay attention to my public number: procedures those things, more wonderful waiting for you! For more, visit www.flydean.com