为什么不编译(尝试使用Java 8和Java 10)?它产生一个丢失的return语句错误。
public class CompilerIssue {
public boolean run() {
throwIAE();
// Missing return statement
}
public void throwIAE() {
throw new IllegalStateException("error");
}
}
答案 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
方法,程序继续。 return
和throw
都与方法本身的范围有关,而不与调用方法有关。您需要:
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();