Java:抛出RuntimeException

7
下面的代码正确吗?我以为编译器会提示我使用throws Exceptionthrows RuntimeException
public void method1() throws NullPointerException { 

        throw new RuntimeException();
    }

我认为这不正确的原因是,NPE是一种运行时异常(RTE),但是RTE不一定是NPE。

那么这个正确在哪里呢?我希望编译器提示我使用throws Exceptionthrows RuntimeException或者throws NumberFormatException

public void method2() throws NullPointerException { 


    throw new NumberFormatException();
}


public void method3() throws Exception { // this is fine, as expected

        throw new RuntimeException();
    }


    public void method4() throws RuntimeException { // this is fine, as expected

        throw new NullPointerException();
    }

    public void method5() throws Exception { // this is fine, as expected

        throw new NullPointerException(); 
    }

答案:

对于 RTE,即使您没有在方法中添加 throws 子句,编译器也不会报错。

public void method6()  { // no compile time errors!!

        throw new NullPointerException(); 
    }

但是,当我们明确地说 'throw new NullPointerException();'时,为什么编译器会忽略它?
这与 'throw new SQLException();' 相同。
如果某个对象被计算为空并在该空对象上调用操作,则不会在运行时抛出异常。
通常,函数必须声明其可能抛出的所有异常,但是RTE可以绕过此规定!
RTE是未经检查的异常。但是,当您说throw new RTE时,仍然是未经检查的?
问题 - 这不是一个缺陷吗?还是请纠正我对为什么会这样的理解。
更新:
请注意,这个问题不涉及已检查的异常和未检查的异常之间的区别。这个问题也不是关于任何类型的异常或错误之间的区别。
问题是为什么标记为RunTimeException的异常没有被处理,或者没有强制编译器处理它。
例如:
public void methodA() { // methodA is not forced to handle the exception.
        methodB(); 
    }

    public void methodB() throws RuntimeException {

    }

谢谢,这里有很多信息,我只涵盖了其中的一部分。但是此刻我脑海中浮现的问题是 - 为什么在Java中,明确抛出的运行时异常被归类为未经检查的异常? - spiderman
1
不要将“unchecked”理解为编译器看不到的东西。它只是表示无需处理。 - Sotirios Delimanolis
抱歉耽误您的时间,但现在我的问题是 - 为什么不处理 RTE?或者说不需要处理? - spiderman
1
因为这就是它们的设计方式。 - Sotirios Delimanolis
1
这个问题太宽泛了,在这里无法回答。如果你真的感兴趣,互联网上有很多关于它的争论。 - Sotirios Delimanolis
显示剩余4条评论
2个回答

12

你误解了。

检查异常是在编译时检查的异常(因此它们的名称为“Checked exceptions”)。因此,如果您有一个抛出BarException异常的doFoo方法,您必须声明该方法会抛出 BarException 异常:

void doFoo() throws BarException { }

未经编译器检查的异常是指不需要声明抛出它们的异常。使用throw new Exception()只会抛出已检查的异常实例,或在RuntimeException的情况下是未经检查的。唯有当您实际使用throw子句抛出已检查的异常时才需要考虑检查因素。

至于是否存在缺陷,这是一个非常主观的话题。使用API抛出大量未经检查的异常却没有记录这些异常往往会让人感到非常烦恼。然而,有时会根据应用程序的独特运行时状态发生异常,您可能无法声明某个特定的已检查的异常可能会被抛出,在这种情况下运行时异常(如NullPointerException)就可以发挥作用了。


谢谢,事实上我对它是什么并不感兴趣,我更想理解这样规范背后的原因。 - spiderman
@prash 需要未检查的异常的原因是...它们被定义为在运行时发生的异常。我无法给你一个明确的工程决策(只有Oracle工程师才能),但我会怀疑这是因为某些异常只能在运行时发生,比如空指针异常,所以未检查的异常是完全必要的。然而,已检查的异常可能是一种设计决策,旨在保护开发人员免受愚蠢的异常相关问题的影响...Java还提供了其他东西的编译器强制执行(例如@overload标记)。 - TTT
谢谢您提供这些详细信息。事实上,我同意我们需要未经检查的异常,例如NullPointerException、ArithmeticException等在运行时执行时发生。我的问题是,当我们显式地抛出一个新的RuntimeException,比如通过throw new RunTimeException()throws RunTimeException,情况就不同了。这与您编写throw new SQLException类似。 - spiderman
1
@prash,你想知道为什么如果你使用“throws”显式声明未检查的异常,Java编译器不会检查这些异常是否被捕获?嗯,是的,如果我们可以通过将它们添加到“throws”子句中将未检查的异常转换为已检查的异常,那将非常酷且非常有用。你问题的答案是,Java编译器无条件地不检查未检查的异常。将未检查的异常添加到throw子句中实际上在编译器级别上并没有任何作用,但当你知道某些RuntimeExceptions是可以预期的时,这是一个好习惯。 - TTT
看着我今天的问题...那时候我是不是太蠢了,竟然指望编译器在未检查的异常上给出提示?我的错!!哈哈 - spiderman

1
我认为我理解了这个问题,您想知道在方法的 throws 子句中包含的任何异常是否不被视为已检查的设计缺陷。
检查异常的核心前提是我们可以在抛出异常的位置告诉是否有人想处理此异常。在某些情况下,例如 NullPointerException 在某些上下文中应该被视为已检查的异常而在其他情况下则不应该,但这个想法始终是一件事或另一件事。此外,在最初包括此功能时,这将需要编写更多的代码,而当时有紧迫的截止日期,而对此进行更改将意味着破坏现有的用户代码。因此,这可能是 Java 没有该功能的原因。

是的,您对我的问题理解正确。不仅在throws子句中,在我们明确说“throw new RunTimeException()”时也是如此。 - spiderman
这个答案也是正确的,因为它明确回答了我的具体问题。 - spiderman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接