是否可以在不添加throws声明的情况下引发异常?


80

我有以下情况。

我有一个从另一个基类继承并覆盖一个方法的Java类。基本方法不会引发异常,因此没有throws ...声明。

现在我自己的方法应该可以引发异常,但是我要么有选择

  • 吞下异常
  • 添加抛出声明

两者都不令人满意,因为第一个会静默忽略异常(好了,我可以执行一些日志记录),第二个会由于方法标头不同而生成编译器错误。

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}

Answers:


97

如果确实需要,可以抛出未经检查的异常而不必声明它们。未检查的异常扩展RuntimeException。扩展的ThrowablesError也未选中,但仅应用于完全无法处理的问题(例如无效的字节码或内存不足)。

作为特定情况,添加UncheckedIOException了Java 8用于包装和重新投掷IOException


1
效果很好,我必须重新抛出RuntimeException,因为异常来自另一个方法,但是效果很好,谢谢。
于尔根Steinblock

42

这是一个把戏:

class Utils
{
    @SuppressWarnings("unchecked")
    private static <T extends Throwable> void throwException(Throwable exception, Object dummy) throws T
    {
        throw (T) exception;
    }

    public static void throwException(Throwable exception)
    {
        Utils.<RuntimeException>throwException(exception, null);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Utils.throwException(new Exception("This is an exception!"));
    }
}

我想知道这是如何工作的?我会做一些研究,但是您有没有什么资源对我有帮助?:-)
holmicz


1
很棒的把戏!此技巧还可以应用于lambda表达式/块,以允许将checked-exception方法分配给SAM接口而无需任何throws声明。
JasonMing

拥有无需处理不安全因素的额外超级奖励。
lscoughlin

为什么需要虚拟参数?另外,如果没有通用方法,是否可以工作?
Kiruahxh

28

第三种选择是选择退出异常检查(就像标准API本身有时要做的一样),然后将检查的异常包装在RuntimeException

throw new RuntimeException(originalException);

您可能要使用的更具体的子类RuntimeException


10

我只想添加一个替代答案,纯粹是仅供参考

是的,有一种throws使用sun.misc.Unsafe该类的方法,可以在不添加声明的情况下引发已检查的异常。以下博客文章对此进行了描述:

在未声明的情况下从方法抛出检查后的异常

样例代码:

public void someMethod() {
  //throw a checked exception without adding a "throws"
  getUnsafe().throwException(new IOException());
}

private Unsafe getUnsafe() {
  try {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    return (Unsafe) field.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

但是,不建议这样做。最好包装一些其他答案中概述的未检查的异常。


3
他们之所以叫那班是有原因的Unsafe
OrangeDog 2010年

4

为什么不抛出未经检查的异常?不必声明。

两种选择是

  • 用一个未检查的异常包装一个检查的异常。
  • 不要让编译器知道您正在抛出已检查的异常,例如Thread.currentThread()。stop(e);
  • 在Java 6中,如果异常是 final并且编译器知道您可能已捕获了哪些已检查的异常。
  • 在Java 7中,如果有效地是最终的,则可以抛出异常,即,您无需在代码中对其进行更改。

当您在代码中引发检查异常并在调用代码中捕获该异常时,后者更为有用,但是它们之间的各层对异常一无所知。


第二种方法也很有趣。但是目前,包装异常正是我所需要的。
于尔根Steinblock


@OrangeDog,您已经阅读了此书,可以告诉我在当前线程上使用stop()与引发已包装的异常之间的区别是什么。;)
Peter Lawrey 2010年

“以下方法在行为上与Java的throw操作完全相同,但是绕过了编译器试图确保调用方法已声明所有可能抛出的检查异常的尝试”如何更好地包装该异常?
彼得·劳瑞

“停止线程会使它解锁所有已锁定的监视器。如果以前受这些监视器保护的任何对象处于不一致状态,则其他线程现在可能会以不一致状态查看这些对象。其他未经检查的异常,用户不会警告其程序可能已损坏。”
OrangeDog 2010年

4

是的,有一个原因,但是完全不建议您使用:

Java不安全包

getUnsafe().throwException(new IOException());

此方法抛出检查异常,但是您的代码没有被强制捕获或重新抛出它。就像运行时异常一样。


2

这是一个拦截已检查的异常并将其包装在未检查的异常中的示例:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}

-1

您可以在覆盖的方法中使用try-catch块捕获异常。那么您无需声明throws-语句。


2
当然可以,但是我会吞下这个例外,这与我要达到的目标完全相反;)
JürgenSteinblock 10年

-1

您可以使用从RuntimeException或RuntimeException本身派生的任何异常

要么

使用try块进行异常抛出代码并在那里进行处理

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.