有没有办法注释一个方法,以便所有抛出的异常都自动转换为运行时异常?
@MagicAnnotation
// no throws clause!
void foo()
{
throw new Exception("bar")'
}
有没有办法注释一个方法,以便所有抛出的异常都自动转换为运行时异常?
@MagicAnnotation
// no throws clause!
void foo()
{
throw new Exception("bar")'
}
Project Lombok's@SneakyThrows
可能是您正在寻找的。并没有真正包装您的异常(因为在很多情况下它可能是一个问题),它只是在编译期间不会引发错误。
@SneakyThrows
void foo() {
throw new Exception("bar")'
}
您可以使用 AspectJ 做到这一点。您声明一个连接点(在这种情况下调用方法 foo)并“软化”异常。
编辑详细说明一下:
假设您有以下课程Bar
:
public class Bar {
public void foo() throws Exception {
}
}
...你有一个这样的测试:
import junit.framework.TestCase;
public class BarTest extends TestCase {
public void testTestFoo() {
new Bar().foo();
}
}
那么显然测试不会编译。它会报错:
Unhandled exception type Exception BarTest.java(line 6)
现在要使用 AspectJ 克服这个问题,您可以编写一个非常简单的方面:
public aspect SoftenExceptionsInTestCode {
pointcut inTestCode() : execution(void *Test.test*());
declare soft : Exception : inTestCode();
}
方面基本上是说,AspectJ 编译器应该接受来自测试中的任何代码(即:在以“Test”结尾并返回“void”的类中以“test”开头的方法)抛出异常。如果发生异常,它将被RuntimeException
AspectJ 编译器包装并作为 a 抛出。
事实上,如果您在 Eclipse(安装了 AJDT)中将这个测试作为 AspectJ 项目的一部分运行,那么测试将会成功,而如果没有切面,它甚至无法编译。
我认为可以通过字节码重新设计、定制编译器或面向方面的编程1来实现。与 Java 不同,C# 只有未经检查的异常2。
请问你为什么要抑制检查的异常?
1根据Maarten Winkels的说法,这是可能的。
2并且根据第 9 频道的一些视频,他们正在考虑引入已检查的。
编辑:对于问题:从某种意义上说,您可以注释您的方法以将它们标记为检查异常抑制的候选者。然后你使用一些编译时间或运行时技巧来应用实际的抑制/包装。
但是,由于我没有看到您的案例周围的环境,以这些方式包装异常可能会使该方法的客户感到困惑 - 他们可能不准备处理 RuntimeException。例如:该方法抛出 IOException 并且您的客户端将其捕获为 FileNotFoundException 以显示错误对话框。但是,如果将异常包装到 RuntimeException 中,则永远不会显示错误对话框,并且可能还会杀死调用者线程。(恕我直言)。
Checked 异常是方法实现的责任。非常非常小心地对待这个事实。如果您不能使用这样的解决方法工件。
没办法做到这一点,至少现在我使用这样的解决方法(简化):
@SuppressWarnings({"rawtypes", "unchecked"})
public class Unchecked {
public static interface UncheckedDefinitions{
InputStream openStream();
String readLine();
...
}
private static Class proxyClass = Proxy.getProxyClass(Unchecked.class.getClassLoader(), UncheckedDefinitions.class);
public static UncheckedDefinitions unchecked(final Object target){
try{
return (UncheckedDefinitions) proxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (target instanceof Class){
return MethodUtils.invokeExactStaticMethod((Class) target, method.getName(), args);
}
return MethodUtils.invokeExactMethod(target, method.getName(), args);
}
});
}
catch(Exception e){
throw new RuntimeException(e);
}
}
}
用法如下:
import static ....Unchecked.*;
...
Writer w = ...;
unchecked(w).write(str, off, len);
诀窍是接口“永远不会完成”,每次我需要在某处未经检查的方法时,我都会将该对象包装成未经检查的对象,并让 IDE 在接口中生成方法签名。
然后实现是通用的(反射和“慢”但通常足够快)
有一些代码后处理器和字节码编织器,但这对于我当前的项目来说是不可能的(甚至是 aop 或其他基于 jvm 的语言),所以这是“发明的”。
Class.newInstance
在任何情况下,您都可以通过使用不Exception
将无参数构造函数抛出的事实包装在InvocationTargetException
;中来做到这一点。而是默默地抛出它:
class ExUtil {
public static void throwSilent(Exception e) { //NOTICE NO THROWS CLAUSE
tl.set(e);
SilentThrower.class.newInstance(); //throws silently
}
private static ThreadLocal<Exception> tl = new ThreadLocal<Exception>();
private static class SilentThrower {
SilentThrower() throws Exception {
Exception e = tl.get();
tl.remove();
throw e;
}
}
}
然后您可以在任何地方使用此实用程序:
ExUtil.throwSilent(new Exception());
//or
try {
ioMethod();
} catch (IOException e) { ExUtil.throwSilent(e); }
顺便说一句,这是一个非常糟糕的主意:-)
我使用 Eclipse 的完成/模板系统来轻松包装任何代码块。
这是我的模板:
try { // Wrapp exceptions
${line_selection}${cursor}
} catch (RuntimeException e) { // Forward runtime exception
throw e;
} catch (Exception e) { // Wrap into runtime exception
throw new RuntimeException(
"Exception wrapped in #${enclosing_method}",
e);
}