9

有没有办法注释一个方法,以便所有抛出的异常都自动转换为运行时异常?

@MagicAnnotation
// no throws clause!
void foo()
{
  throw new Exception("bar")'
}
4

7 回答 7

7

Project Lombok's@SneakyThrows可能是您正在寻找的。并没有真正包装您的异常(因为在很多情况下它可能是一个问题),它只是在编译期间不会引发错误。

@SneakyThrows
void foo() {
    throw new Exception("bar")'
}
于 2012-11-30T11:19:14.530 回答
3

您可以使用 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”开头的方法)抛出异常。如果发生异常,它将被RuntimeExceptionAspectJ 编译器包装并作为 a 抛出。

事实上,如果您在 Eclipse(安装了 AJDT)中将这个测试作为 AspectJ 项目的一部分运行,那么测试将会成功,而如果没有切面,它甚至无法编译。

于 2009-06-27T10:45:54.660 回答
1

我认为可以通过字节码重新设计、定制编译器或面向方面的编程1来实现。与 Java 不同,C# 只有未经检查的异常2

请问你为什么要抑制检查的异常?

1根据Maarten Winkels的说法,这是可能的。
2并且根据第 9 频道的一些视频,他们正在考虑引入已检查的。

编辑:对于问题:从某种意义上说,您可以注释您的方法以将它们标记为检查异常抑制的候选者。然后你使用一些编译时间或运行时技巧来应用实际的抑制/包装。

但是,由于我没有看到您的案例周围的环境,以这些方式包装异常可能会使该方法的客户感到困惑 - 他们可能不准备处理 RuntimeException。例如:该方法抛出 IOException 并且您的客户端将其捕获为 FileNotFoundException 以显示错误对话框。但是,如果将异常包装到 RuntimeException 中,则永远不会显示错误对话框,并且可能还会杀死调用者线程。(恕我直言)。

于 2009-06-27T10:46:28.857 回答
1

Checked 异常是方法实现的责任。非常非常小心地对待这个事实。如果您不能使用这样的解决方法工件。

于 2011-05-10T16:06:01.890 回答
1

没办法做到这一点,至少现在我使用这样的解决方法(简化):

@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 的语言),所以这是“发明的”。

于 2012-06-11T19:31:38.330 回答
0

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); }

顺便说一句,这是一个非常糟糕的主意:-)

于 2009-06-27T13:32:14.510 回答
0

我使用 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); 
}
于 2011-05-03T09:37:06.490 回答