Exception handling in Java 8 lambda expressions

Exception handling in Java 8 lambda expressions

brief introduction

Lambda expressions are introduced into Java 8. Lambda expressions can make our code more brief and business logic clearer. However, the functional interfaces used in lambda expressions do not handle exceptions well, because these functional interfaces provided by JDK usually do not throw exceptions, which means that we need to handle exceptions manually.

Because exceptions are divided into unchecked exception and checked exception, we will discuss them separately.

Handling unchecked exception

Unchecked exception is also called runtimeException. RuntimeException usually occurs because there is a problem with our code. RuntimeException does not need to be caught. That is, if there is a runtimeException, it can also be compiled without capture.

Let's take an example:

@H_301_33@List<Integer> integers = Arrays.asList(1,2,3,4,5);
        integers.forEach(i -> System.out.println(1 / i));

This example can be compiled successfully, but there is a problem above. If there is a 0 in the list, an arithmeticexception will be thrown.

Although this is an unchecked exception, we still want to handle it:

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

In the above example, we use try and catch to handle exceptions, which is simple but destroys the best practice of lambda expressions. The code becomes bloated.

We move try and catch to a wrapper method:

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

Then the original call becomes as follows:

@H_301_33@integers.forEach(lambdaWrapper(i -> System.out.println(1 / i)));

However, the wrapper above is fixed to capture arithmeticexception, and we will adapt it into a more general class:

@H_301_33@    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) {
                    throw ex;
                }
            }
        };
    }

The above class passes in a class and casts it to an exception. If it can be cast, it will be handled. Otherwise, an exception will be thrown.

After this processing, we call:

@H_301_33@integers.forEach(
                consumerWrapperWithExceptionClass(
                        i -> System.out.println(1 / i),ArithmeticException.class));

Handling checked exception

Checked exception is an exception that must be handled. Let's take an example:

@H_301_33@    static void throwIOException(Integer integer) throws IOException {
    }
@H_301_33@List<Integer> integers = Arrays.asList(1,5);
        integers.forEach(i -> throwIOException(i));

We defined a method above to throw IOException, which is a checked exception and needs to be handled. Therefore, in the following foreach, the program will fail to compile because the corresponding exception is not handled.

The simplest way is to try and catch, as shown below:

@H_301_33@        integers.forEach(i -> {
            try {
                throwIOException(i);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });

Of course, we have already mentioned the disadvantages of this method. Similarly, we can define a new wrapper method:

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

        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

We call:

@H_301_33@integers.forEach(consumerWrapper(i -> throwIOException(i)));

We can also encapsulate the following exceptions:

@H_301_33@static <T,E extends Exception> Consumer<T> consumerWrapperWithExceptionClass(
            ThrowingConsumer<T,E> throwingConsumer,Class<E> 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 new RuntimeException(ex);
                }
            }
        };
    }

Then call:

@H_301_33@integers.forEach(consumerWrapperWithExceptionClass(
                i -> throwIOException(i),IOException.class));
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>