Handle exceptions coolly with Java 8 lambda expressions and Stream API

In Java 8 Collection and Stream API, Iteratable is implemented, and in the for statement You can now use lambda expressions for the part you were calculating.

However, Functional Interfaces such as Consumer are not defined to throw an exception. So the inability to throw a CheckedException (https://qiita.com/shunsuke227ono/items/142703c0b046f522f8bd) is a drawback of the lambda expression (https://teratail.com/questions/). It is said to be 8461). Wrapping or squeezing checked exceptions into runtime exceptions that are not checked at compile time is not good from an exception handling perspective. ..

Qiita and Stackoverflow Also i ku [tsu](https://qiita.com /yoshi389111/items/c6b7d373a00f8fd3d5f3) or A solution is presented, but [grabbing inspection exceptions](https://s //github.com/SeregaLBN/StreamUnthrower), the lambda is a poorly visible code, [heavy implementation per function interface](https://github.com/fge/throwing- lambdas / tree / master / src / main / java / com / github / fge / lambdas / consumers) or not. By Google teacher and everyone is worried / (´ω `;) \

Rethrow by supplementing Runtime Exception (I don't want to)

Unwrap Runtime in CheckException. I don't want to do this because the code is out of sight ...

try {
  Arrays.asList(1, 2, 3).forEach(e -> {
    try { 
      //Some business logic that throws checked exception
      methodTrowingIOException(e.intValue());
    } catch(IOException ex) {
      // throw new UncheckedIOException(ex);      
      throw new RuntimeException(ex);
    }
  }));
} catch (RuntimeException re) {
  Throwable e = re.getCause();//Throw check exception
  throw e;
}

You can use UncheckedIOException, but unwrapping is troublesome and RuntimeException is used. It's not much different from.

Define a FunctionalInterface with an Exception in the throws clause

@FunctionalInterface
public interface CheckedFunction<T, R> {
   R apply(T t) throws Exception;
}

void foo (CheckedFunction f) { ... }

However, this is a [for Each](https: /) that assumes Consumer. /docs.oracle.com/javase/jp/8/docs/api/java/lang/Iterable.html#forEach-java.util.function.Consumer-) etc., so rejected.

Sneaky throw Use idioms to handle checked exceptions

Sneaky throw is a Java compiler type-checking secret that tricks a checked exception into a RuntimeException at compile time [Lombok]( This is the technique used at https://qiita.com/opengl-8080/items/671ffd4bf84fe5e32557). This article is detailed.

@SuppressWarnings("unchecked")
@Nonnull
public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
    throw (E) ex;
}

//I'm throwing an IOException, but I don't need throws or catch because the compiler tricks me into a RuntimeException, but it actually throws an IOException.
@Test(expected = IOException.class)
public void testSneakyThrow() {
    Throwing.sneakyThrow(new IOException());
}

Applying this idiom, we define the following Consumer.

import java.util.function.Consumer;

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T e) {
        try {
            accept0(e);
        } catch (Throwable ex) {
            Throwing.sneakyThrow(ex);
        }
    }

    void accept0(T e) throws Throwable;
}

When using it, do as follows. To receive lambda, use the above Throwing Consumer that inherits the Consumer interface. This is an advanced version of StackOverflow Answer.

    @Test
    public void testThrowingConsumer() throws IOException {
        thrown.expect(IOException.class);
        thrown.expectMessage("i=3");

        Arrays.asList(1, 2, 3).forEach((ThrowingConsumer<Integer>) e -> {
            int i = e.intValue();
            if (i == 3) {
                throw new IOException("i=" + i);
            }
        });
    }

More concise representation using the Rethrow static method

With Throwing Consumer, the part that receives the lambda expression in For Each with Throwing Consumer was a little complicated to express. I want to make this more concise.

public final class Throwing {

    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }
}

Just wrap your lambda expression with the rethrow method. This is my final answer so far.

The compiler assumes that forEach will only throw a runtime exception, so either throws IOException at the caller or try / catch at the right time.

import static hivemall.utils.lambda.Throwing.rethrow;

    @Test
    public void testRethrow() throws IOException {
        thrown.expect(IOException.class);
        thrown.expectMessage("i=3");

        Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
            int i = e.intValue();
            if (i == 3) {
                throw new IOException("i=" + i);
            }
        }));
    }

Please let me know if there is a better way.

Recommended Posts

Handle exceptions coolly with Java 8 lambda expressions and Stream API
Nowadays Java lambda expressions and Stream API
How to handle exceptions coolly with Java 8 Stream or Optional
[For beginners] About lambda expressions and Stream API
Use Java lambda expressions outside of the Stream API
Java lambda expressions learned with Comparator
Handle Java 8 date and time API with Thymeleaf with Spring Boot
Rethinking design patterns with Java8 lambda expressions & Stream --Builder pattern -
Getting started with Java lambda expressions
Java Stream API
[Java] Get Json from URL and handle it with standard API (javax.script)
Java8 / 9 Beginners: Stream API addiction points and how to deal with them
Interact with LINE Message API using Lambda (Java)
How to use Java API with lambda expression
[Java] Stream API / map
Understand Java 8 lambda expressions
Java8 Stream API practice
About Java lambda expressions
Explain Java 8 lambda expressions
[In-house study session] Java basics-Lambda expression and Stream API- (2017/07/13)
Getting Started with Legacy Java Engineers (Stream + Lambda Expression)
Use Lambda Layers with Java
Have fun programming with lambda expressions and a fluid interface
Java Stream API cheat sheet
Java Stream API in 5 minutes
Java8 stream, lambda expression summary
[Java] Introduction to lambda expressions
Create a SlackBot with AWS lambda & API Gateway in Java
[Java] Stream API --Stream termination processing
[Java] Stream API --Stream intermediate processing
[Java] Introduction to Stream API
Convert 2D array to csv format with Java 8 Stream API
[Java] Stream API intermediate operation
[Java 8] Duplicate deletion (& duplicate check) with Stream
Use java with MSYS and Cygwin
Distributed tracing with OpenCensus and Java
Install Java and Tomcat with Ansible
[Introduction to Java] About lambda expressions
[java8] To understand the Stream API
Java for beginners, expressions and operators 1
About Lambda, Stream, LocalDate of Java8
[Introduction to Java] About Stream API
Use JDBC with Java and Scala.
[Java] Element existence check with Stream
Java for beginners, expressions and operators 2
Output PDF and TIFF with Java 8
I tried using Java8 Stream API
Java 8 ~ Stream API ~ to start now
The origin of Java lambda expressions
Encrypt with Java and decrypt with C #
How to use Java lambda expressions
Java8 list conversion with Stream map
[Salesforce] Registering and updating static resources with Tooling API (Java sample SOAP API)
I wrote a Lambda function in Java and deployed it with SAM
Data processing using stream API from Java 8
API integration from Java with Jersey Client
I tried to summarize Java lambda expressions
Try using the Stream API in Java
Link Java and C ++ code with SWIG
Let's try WebSocket with Java and javascript!
[Java] Handle Excel files with Apache POI