抛出RuntimeException时,Java期望返回值

问题描述 投票:3回答:7

为什么这不编译(尝试使用java 8和java 10)?它会产生一个缺少的返回语句错误。

 public class CompilerIssue {
   public boolean run() {
     throwIAE();
     // Missing return statement
   }

   public void throwIAE() {
     throw new IllegalStateException("error");
   }
 }
java aop javac runtimeexception
7个回答
14
投票

java编译器不知道throwIAE将始终抛出异常,因此它假设您最终将到达run方法的末尾,并且当发生这种情况时,需要返回值。


6
投票

你的方法有一个返回类型,所以它应该返回一个布尔结果。

   public boolean run() {
     throwIAE();
     // Missing return statement
     return false;
   }

或者你应该直接在方法中抛出异常:

   public boolean run() {
     throw new IllegalStateException("error"); // it will compile
   }

3
投票

即使编译器现在很聪明,他们也不能“看到”你的throwIAE()方法总是返回一个异常,因为这将在运行时而不是编译时发生。如果处理异常怎么办?然后,您必须最终添加返回值。


1
投票

抛出的异常终止了throwIAE方法,但没有终止调用此方法的方法。将此理解为返回输出的方法(自return;以来空void)。

public void throwIAE() {
     return;                // is not responsible for terminating run()
}

你有看到? return终止throwIAE方法,程序继续。 returnthrow都与方法本身的范围有关,而不是调用方法。你需要:

public boolean run() {
     throwIAE();            // throws exception and terminates throwIAR()
     return false;          // terminates run()
}

1
投票

到目前为止答案很好。我想知道没人提到AOP(面向方面​​编程)。使用AOP,您可以在RUNTIME期间轻松拦截您的方法throwIAE()并捕获异常。调用方法run()无法知道这一点。

一些例子:

package yourPackage;

public class YourClass {

    public boolean run() {
        throwIAE();
        System.out.println("Hello world!");// prints Hello World! even if method throws exception
        return false;// does not compile without return statement
    }

    public void throwIAE() {
        throw new IllegalStateException("error");
    }

}

另一个Aspect类在运行时拦截throwIAE()方法:

package yourPackage;

@Aspect
public class ExceptionHandlingAspect {
    @Around("execution(* yourPackage.YourClass.throwIAE())")
    public Object handleException(ProceedingJoinPoint pjp) throws Throwable {
        try {
            return pjp.proceed();
        } catch (Exception e) {
            System.out.println("exception caught");
            return null;
        }
    }
}  

0
投票

虽然其他答案从用户的角度正确解释了这种情况,但值得注意的是,分析此类流程的“聪明”并非由编译器自行决定,而是由JLS规则精确定义。特别是,§14.21包含:

如果表达式可以访问,则表达式语句可以正常完成。

throwIAE()这样的方法调用是一个表达式语句,因为它在示例中是可达的,所以它也可以“正常完成”。因此,方法体可以“正常完成”,根据§8.4.7,对于具有非void返回类型的方法是非法的(也就是说,此类方法必须在所有可能的路径上返回值)。

换句话说,JLS定义了在流分析期间所有方法调用都被平等对待,并且没有“方法 - 总是抛出”这样的概念。


0
投票

想象一下:

 public class NotReallyACompilerIssue extends CompilerIssue {

   @Override    
   public void throwIAE() {
     // doesn't really throw the IAE!
   }
 }

如果您的原始类在run()中没有返回语句而编译,则run()中的NotReallyACompilerIssue方法已成功完成且无法返回。哪个不好,是吗?

如果类isfinal或方法throwIAE isfinal,则可以检测到这种情况。但情况并非如此,编译器(至少Oracle J8_131)不会进行此类检查。我想这是一个非常具体的案例,不值得努力。

© www.soinside.com 2019 - 2024. All rights reserved.