从Lambda重新抛出异常

huangapple go评论72阅读模式
英文:

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&lt;EntityCondition&gt; conditions)
      throws UnsatisfiedConditionException {
    conditions.forEach(
       consumerWrapper(
           entityCondition -&gt; {
              throw new UnsatisfiedConditionException(entityCondition);
           }, UnsatisfiedConditionException.class));
}

Which throws an exception and having this consumer:

public interface ThrowingConsumer&lt;T&gt; {
  void accept(T t) throws Exception;
}

And wrapper:

public static &lt;T, E extends Exception&gt; Consumer&lt;T&gt; consumerWrapper(
      ThrowingConsumer&lt;T&gt; consumer, Class&lt;E&gt; clazz) {
    return i -&gt; {
      try {
        consumer.accept(i);
      } catch (Exception ex) {
        ex.printStackTrace();
        try {
          E exCast = clazz.cast(ex);
          System.err.println(
              &quot;Exception occurred : &quot; + 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 Consumers, 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&lt;T, E extends Throwable&gt; {
    void accept(T t) throws E;
}

...

public static &lt;T, E extends Exception&gt; Consumer&lt;T&gt; consumerWrapper(
            ThrowingConsumer&lt;T, E&gt; consumer, Class&lt;E&gt; 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&lt;T&gt; extends Consumer&lt;T&gt;{
  @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 &lt;T&gt; Consumer&lt;T&gt; rethrow(@Nonnull final ThrowingConsumer&lt;T&gt; consumer) {
    return consumer;
  }

  @SuppressWarnings(&quot;unchecked&quot;)
  @Nonnull
  public static &lt;E extends Throwable&gt; void sneakyThrow(@Nonnull Throwable ex) throws E {
    throw (E) ex;
  }

}

And use it like this:

public static void processConditions(@NotNull List&lt;EntityCondition&gt; conditions)
      throws UnsatisfiedConditionException {
    conditions.forEach(
       rethrow(
           entityCondition -&gt; {
              throw new UnsatisfiedConditionException(entityCondition);
           }, UnsatisfiedConditionException.class));
}

huangapple
  • 本文由 发表于 2020年10月23日 13:27:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/64494346.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定