抛出异常时,函数的返回类型可以是异常

问题描述 投票:2回答:4

假设我有一个功能

private RuntimeException foo() {
    return new RuntimeException();
}

并且没有抛出异常,可以像处理一样处理

throw foo();

或者可以将返回值赋给变量

RuntimeException e = foo();

但是功能可以改为

private RuntimeException foo() {
    throw new RuntimeException();
}

它仍然可以编译,可以像以前的例子一样使用,也可以像foo();一样调用,并抛出Exception。

但是为什么有可能将RuntimeException指定为不返回它的方法的返回类型,而是将其抛出。在这种情况下,抛出和返回行为之间是否有任何联系?

我注意到有Exception(或更常见的Throwable)返回类型确保它将在每个决策分支中抛出/返回,如if / else语句。但有更实际的用法或推荐吗?

java
4个回答
2
投票

由于throw将使方法的执行立即停止并且控制权被传递回调用者,因此返回的方法无关紧要。无论您返回什么类型,都不会返回该类型,因为您在第一行上抛出异常(表示发生了错误)。

编译器允许这样做,因为抛出异常意味着发生了错误,例如参数无效,或者参数为null,依此类推。在这种错误条件下,编译器不希望该方法正常返回值。这是有道理的,因为很明显,当出现错误时,该方法无法计算它将要计算的任何内容。

所以短语“所有代码路径必须返回一个值”应该说“所有代码路径必须返回一个值或抛出一个Throwable”。


0
投票

方法返回的内容与它可以抛出的内容之间没有关系。并且有一些用例,其中一个方法可以返回并抛出异常。

请考虑以下情形:调用以生成特定于应用程序的异常的方法:

public Exception produceException(User u) {
    if (u.id == null) return new UserNotFoundException();
    if (u.name == null) return new UserDidNotCompleteRegistrationException();
    if (u.email == null) return new UserDidNotVerifyEmailException();
}

现在猜猜如果论证本身是null会发生什么?并且该方法甚至没有声明throws条款......

现在,关于将Exception作为返回值以确保在每个分支返回异常只是糟糕的设计。返回值不是用于抛出异常的机制。如果用try-catch包围整个方法体,你将捕获所有分支的所有异常。


0
投票

为什么可以将RuntimeException指定为不返回它但返回它的方法的返回类型。在这种情况下,抛出和返回行为之间是否有任何联系?

可以将任何类型指定为任何方法的返回类型。 return和throw行为之间没有联系。

我注意到具有Exception(或更普遍的Throwable)返回类型确保它将在每个决策分支中抛出/返回,如if / else语句

不,事实并非如此。没有办法“确保每个决策分支都会抛出[异常]”。你唯一能做的就是声明“这个方法可能会使用throws关键字抛出异常:

public void mightThrowException() throws Exception {...}

但是不能保证任何异常都会被抛出。

顺便说一下,有两种类型的例外:已选中和未选中。未经检查的例外是RuntimeException的子类;那些不需要为您的方法声明。检查异常是这样做的

public void throwsIoException() {
    throw new IOException();
}

是非法的,因为IOException是一个经过检查的例外,需要用throws声明。


0
投票

你把一些东西与你的例子混在一起。因为在方法中抛出异常时,实际上并未考虑返回类型,因此不会像示例中那样声明方法。你也可以声明如下:

public void foo(){
    throw new RuntimeException();
}

要么:

public MyComplexType foo2(){
    throw new RuntimeException();
}

结果完全相同:抛出异常。调用代码看起来会有所不同,例如:

foo(); // throws RuntimeException
myOtherComputation(); // is never reached

要么

MyComplexType type = foo2(); // throws RuntimeException
type.doSomething(); // is never reached

当在方法中使用例如switch语句但在输入默认分支时抛出错误时,此行为非常有用:

public String foo(String string){
    switch(string){
        case "foo":
             return "bar";
        case "bar":
             return "foo";
        default:
            throw new UnsupportedOperationException("Unknown string: '" + string + "'!");
     }
}
© www.soinside.com 2019 - 2024. All rights reserved.