抛出RuntimeException时,Java需要返回值

时间:2018-08-27 17:35:20

标签: java aop javac runtimeexception

为什么不编译(尝试使用Java 8和Java 10)?它产生一个丢失的return语句错误。

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

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

8 个答案:

答案 0 :(得分:14)

java编译器不知道 throwIAE 总是会抛出异常,所以它 假设您最终将到达 run 方法和 当那件事发生时 返回值是必需的。

答案 1 :(得分:6)

您的方法具有返回类型,因此应返回布尔结果。

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

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

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

答案 2 :(得分:3)

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

答案 3 :(得分: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()
}

答案 4 :(得分: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");
    }

}

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

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;
        }
    }
}  

答案 5 :(得分:0)

尽管其他答案可以从用户的角度正确地解释这种情况,但值得注意的是,分析此类流的“明智性”不是由编译器决定的,而是由JLS规则精确定义的。特别是§14.21包含以下内容:

  

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

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

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

答案 6 :(得分:0)

想象一下:

 public class NotReallyACompilerIssue extends CompilerIssue {

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

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

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

答案 7 :(得分:0)

我并不是真的希望它能起作用,但是有趣的是您可以做到这一点,这使代码更具可读性:

    public static <T> T unsupported()
    {
        throw new UnsupportedOperationException();
    }

     ...
    
    return unsupported();