在我正在从事的项目中,我发现了一个类,该类将其超类的所有方法包装在一些精心设计的异常处理中。看起来类似于:
@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>
。
我尝试向Exception
和ThrowingMethod
添加更多通用参数,但是它没有任何改变。
如何使功能接口与多个通用异常一起使用?
答案 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。您只需要创建一个匹配所有这些方法的切入点,就不会有很多重复的样板。不需要这些接口或包装方法。