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

时间:2018-03-02 09:21:50

标签: java

假设我有一个功能

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

并且没有抛出异常,它可以像

一样处理
throw foo();

或返回值可以分配给变量

RuntimeException e = foo();

但是该功能可以改为

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

并且它仍然可以编译并且可以像之前的示例一样使用,或者可以像foo();一样调用,并且将抛出异常。

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

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

4 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分: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包围整个方法体,你将捕获所有分支的所有异常。

答案 2 :(得分:0)

  

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

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

  

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

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

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

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

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

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

是非法的,因为IOException是需要使用throws声明的已检查异常。

答案 3 :(得分: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 + "'!");
     }
}