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 / (´ω `;) \
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.
@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 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);
}
});
}
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