Java 8-在Lambda中抛出多个泛型检查异常

时间:2018-09-28 15:11:47

标签: java lambda java-8 exception-handling

在我正在从事的项目中,我发现了一个类,该类将其超类的所有方法包装在一些精心设计的异常处理中。看起来类似于:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@NodeEntity
public class FieldsFrom {
   @Id
   @GeneratedValue
   private Long id;

   private String name;


   @Relationship(type= "USED_BY", direction = Relationship.INCOMING)
   private Set<FieldsTo> fieldsTo;

}

我马上就说:“哇,如果有一个通用包装器,而在所有这些方法中都调用它,那将是怎么回事。该类大约要短10倍!”。 所以我开始工作。

这就是我被困住的地方:

public void method1() throws ExceptionA {
    String exceptionString = "";
    try {
        super.method1();
    } catch (ExceptionA e) {
         exceptionString = // <convert the exception to string in an elaborate way>
         throw e;
    } finally {
         // <an elaborate logger call which uses value of exceptionString>
    }
}

public void method2() throws ExceptionB, ExceptionC {
    String exceptionString = "";
    try {
        super.method2();
    } catch (ExceptionB | ExceptionC e) {
         exceptionString = // <convert the exception to string in elaborate way>
         throw e;
    } finally {
         // <an elaborate logger call which uses value of exceptionString>
    }
}

// ... <a bunch of other methods like this>

最后,此方法适用于仅引发一种类型的已检查异常的方法。当方法抛出多个检查的异常时,Java会假定异常类型为private interface ThrowingMethod<E extends Exception> { void run() throws E; } public <E extends Exception> void wrapMethod(ThrowingMethod<E> method) throws E { String exceptionString = ""; try { method.run(); } catch (Exception e) { exceptionString = // <convert the exception to string in an elaborate way> throw e; } finally { // <an elaborate logger call which uses value of exceptionString> } } public void method1() throws ExceptionA { wrapMethod(super::method1); // works } public void method2() throws ExceptionB, ExceptionC { wrapMethod(super::method2); // Error in Eclipse: "Unhandled exception type Exception" } // ... <a bunch of other methods like this>

我尝试向ExceptionThrowingMethod添加更多通用参数,但是它没有任何改变。

如何使功能接口与多个通用异常一起使用?

2 个答案:

答案 0 :(得分:3)

当您扩展界面以使用两个类型变量时,即

private static interface ThrowingMethod<E1 extends Exception,E2 extends Exception> {
    void run() throws E1, E2;
}

public <E1 extends Exception,E2 extends Exception>
void wrapMethod(ThrowingMethod<E1,E2> method) throws E1,E2 {
    // same as before
}

关于类型推断的规则不会改变,并且对于两个类型变量而言,它们是相同的。例如。您仍然可以使用

public void method1() throws ExceptionA {
    wrapMethod(super::method1);
}

和以前一样,因为编译器只是为两个类型变量推断相同的单个异常类型。

对于声明两个异常的方法,它不会为第一个类型变量选择一个,而为第二个类型变量选择另一个;没有规则可以告诉编译器哪个异常用于哪个类型变量。

但是在这种情况下,您可以帮助编译器,例如

public void method2() throws ExceptionB, ExceptionC {
    wrapMethod((ThrowingMethod<ExceptionB, ExceptionC>)super::method2);
}

这是使用此方法可获得的最好结果。

答案 1 :(得分:0)

因此,您的目标只是使用日志记录包装一堆方法?一种典型的处理方法是使用AOP。您只需要创建一个匹配所有这些方法的切入点,就不会有很多重复的样板。不需要这些接口或包装方法。