英文:
Rethrow exceptions from Lamdba
问题
以下是翻译好的内容:
我有这段代码:
public static void processConditions(@NotNull List<EntityCondition> conditions)
throws UnsatisfiedConditionException {
conditions.forEach(
consumerWrapper(
entityCondition -> {
throw new UnsatisfiedConditionException(entityCondition);
}, UnsatisfiedConditionException.class));
}
它会抛出一个异常,其中有这个 consumer:
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
以及包装器:
public static <T, E extends Exception> Consumer<T> consumerWrapper(
ThrowingConsumer<T> consumer, Class<E> clazz) {
return i -> {
try {
consumer.accept(i);
} catch (Exception ex) {
ex.printStackTrace();
try {
E exCast = clazz.cast(ex);
System.err.println("Exception occurred : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
//throw ex;
}
}
};
}
通过这个 consumerWrapper
可以吞没 lambda 抛出的异常,然而我需要它能够“重新抛出”它,因此需要 throw ex;
。因此,在这里的 processConditions
方法可能会抛出它。
如何实现这一点呢?
英文:
I have this code:
public static void processConditions(@NotNull List<EntityCondition> conditions)
throws UnsatisfiedConditionException {
conditions.forEach(
consumerWrapper(
entityCondition -> {
throw new UnsatisfiedConditionException(entityCondition);
}, UnsatisfiedConditionException.class));
}
Which throws an exception and having this consumer:
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
And wrapper:
public static <T, E extends Exception> Consumer<T> consumerWrapper(
ThrowingConsumer<T> consumer, Class<E> clazz) {
return i -> {
try {
consumer.accept(i);
} catch (Exception ex) {
ex.printStackTrace();
try {
E exCast = clazz.cast(ex);
System.err.println(
"Exception occurred : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
//throw ex;
}
}
};
}
With this consumerWrapper
can swallow the exceptions thrown by the lambda, however I need it to "rethrow" it, thus throw ex;
As such the method processConditions
here can throw it.
How can that be achieved?
答案1
得分: 1
以下是翻译好的内容:
无法正常工作的原因是无法在普通的“Consumer”中抛出已检查的异常,并且“ex”可能是已检查的异常。
一个简单的解决方法是抛出一个未经检查的“RuntimeException”,原因是“ex”:
throw new RuntimeException(ex);
请注意,这将与仅抛出“ex”产生稍有不同的错误消息。它将显示“java.lang.RuntimeException
”,后跟“RuntimeException”的堆栈跟踪,然后是“由WhateverExceptionExIs
引起”...,后跟“WhateverExceptionExIs”的堆栈跟踪。
您可以通过为“ThrowingConsumer”引入另一个类型参数,使“consumerWrapper”变得更安全:
interface ThrowingConsumer<T, E extends Throwable> {
void accept(T t) throws E;
}
...
public static <T, E extends Exception> Consumer<T> consumerWrapper(
ThrowingConsumer<T, E> consumer, Class<E> clazz) {
这样,就可以在编译时检测出诸如此类的不合理调用:
consumerWrapper(Foo::thisThrowsExceptionFoo, ExceptionBar.class);
英文:
The reason why throwing ex
doesn't work is because you can't throw checked exceptions in regular Consumer
s, and ex
could be a checked exception.
A simple workaround would be to throw an unchecked RuntimeException
, with the cause being ex
:
throw new RuntimeException(ex);
Note that this will create a slightly different error message from just throwing ex
. It will say "java.lang.RuntimeException
" followed by the stack trace of the RuntimeException
, followed by "Caused by WhateverExceptionExIs
..." followed by the stack trace of WhateverExceptionExIs
.
You can make your consumerWrapper
a bit safer by introducing another type parameter to ThrowingConsumer
:
interface ThrowingConsumer<T, E extends Throwable> {
void accept(T t) throws E;
}
...
public static <T, E extends Exception> Consumer<T> consumerWrapper(
ThrowingConsumer<T, E> consumer, Class<E> clazz) {
So that silly calls like this can be detected at compile time:
consumerWrapper(Foo::thisThrowsExceptionFoo, ExceptionBar.class);
答案2
得分: 0
这是使其工作的方法:
@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 t) throws Throwable;
}
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;
}
}
并像这样使用它:
public static void processConditions(@NotNull List<EntityCondition> conditions)
throws UnsatisfiedConditionException {
conditions.forEach(
rethrow(
entityCondition -> {
throw new UnsatisfiedConditionException(entityCondition);
}, UnsatisfiedConditionException.class));
}
英文:
Here's how to make it work:
@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 t) throws Throwable;
}
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;
}
}
And use it like this:
public static void processConditions(@NotNull List<EntityCondition> conditions)
throws UnsatisfiedConditionException {
conditions.forEach(
rethrow(
entityCondition -> {
throw new UnsatisfiedConditionException(entityCondition);
}, UnsatisfiedConditionException.class));
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论