为什么此代码缺少返回语句错误?

如果我将此代码的else if部分更改为else语句,它运行没有任何问题,所以我得到了如何使它运行。 我有点困惑的是为什么当它处于当前forms时我得到一个丢失的return语句错误。 我的返回依赖于负的布尔变量的值。 我涵盖了真实和虚假的状态,还不足以涵盖一切吗?

或者是我总是必须在else中有一个return语句或者在函数的底部添加一个无意义的返回true,以便编译器接受我的代码覆盖每个案例?

import java.util.*; import java.lang.*; import java.io.*; class Ideone { public boolean posNeg(int a, int b, boolean negative) { if (!negative) { return (a  0) || (a > 0 && b < 0); } else if (negative) { return (a < 0 && b < 0); } } public static void main (String[] args) throws java.lang.Exception { } } 

当编译器else if没有else或尾随return语句的情况下看到else if ,不能确定所有控制路径都将导致有效的return语句。

编译器有时可能很聪明,但在这种情况下它不能很聪明(也不应该是)。

这种行为在您的示例中很有用: else if在这种情况下,您绝对没有理由使用else if 。 简单的else更容易阅读,更简洁,更不容易出错。

在这种情况下, else非常富有表现力。 这意味着“ 与if子句相反 ”,如果代码将来发生变化,情况仍然如此。

如果编译器允许,您当前的代码将更有可能包含和/或引入错误。

这是我将如何重写方法体:

 if (negative) { return (a < 0 && b < 0); } else { return (a < 0 && b > 0) || (a > 0 && b < 0); } 

一般来说,除非有令人信服的理由(即可读性),否则你应该更喜欢if (negative) if (!negative)

此外,很多人(包括我自己)试图在if / else语句中首先放入最简单的子句。 使代码易于阅读是一件好事。

查看StephenC的答案,获得技术解释以及有关编译器为何如此行为的更多背景信息。

其他问题从直观的角度解释了错误信息的含义。 然而, “编译器很聪明,但并不完美!” 评论缺少重点。

事实上,Java编译器将您的示例称为错误,因为Java语言规范要求它将其称为错误。 Java编译器不允许对此“聪明”


以下是JLS(对于Java 7 1 )实际所说的内容,以及它如何应用于错误示例的简化版本,然后是更正版本。

“如果声明方法具有返回类型,则如果方法的主体可以正常完成( JLS 14.1 ),则会发生编译时错误。换句话说,具有返回类型的方法必须仅通过返回返回提供值返回的语句;不允许“从其主体的末端掉落”。“ – JLS 8.4.7

(阅读JLS 14.1中关于“正常完成”的定义……)

决定“正常”完成是否可能的规则是JLS 14.21中的可达性规则。 他们说:

  1. “if if-then语句可以正常完成,如果它可以访问的话。”
  2. “如果then语句可以正常完成或者else语句可以正常完成,那么if-then-else语句可以正常完成。”
  3. “rest,继续,返回或抛出声明无法正常完成。”

(’iff’的意思是“当且仅当”……)

考虑该示例的简化版本:

  public int test(boolean a) { if (a) { return 1; } else if (!a) { return 0; } } 

在此示例中,else语句是if-then,它可以通过规则#1正常完成。 因此,通过规则#2,if-then-else语句也可以正常完成。 但这是一个编译错误,因为JLS 8.4.7说具有返回类型的方法无法正常完成。

但是,如果您将示例更改为此…

  public int test(boolean a) { if (a) { return 1; } else { return 0; } } 

现在,通过规则#3,if语句和else语句都无法正常完成。 因此,通过规则#2,整个if-then-else无法正常完成。 这就是JLS 8.4.7所要求的……因此没有编译错误。

1 – Java 8 JLS基本上会说同样的东西,虽然章节数可能会有所不同……

我想你已经知道第二个是多余的。

if (negative)被解释为无上下文,这意味着编译器会忽略if(!negative)已被处理。

if => else if => where where条件?

对于return语句, 必须处理所有分支(条件)。

你可以这样做:

 if (!negative) return (a < 0 && b > 0) || (a > 0 && b < 0); return (a < 0 && b < 0); 

要么:

 if (!negative) return (a < 0 && b > 0) || (a > 0 && b < 0) else return (a < 0 && b < 0); 

或(我的首选方式):

 return negative ? (a < 0 && b < 0) : (a < 0 && b > 0 || a > 0 && b < 0) 

但是,我建议避免负面情况,在复杂情况下人脑更难。 甚至像IntelliJ这样的Java IDE也有助于找到这些模式来修复它们。
你最终得到:

 if (negative) return (a < 0 && b < 0); else return (a < 0 && b > 0) || (a > 0 && b < 0); 

你在“else”括号中不需要“if(negative){}”

您应该在所有分支机构中获得回报。

 public boolean posNeg(int a, int b, boolean negative) { if (!negative) { return (a < 0 && b > 0) || (a > 0 && b < 0); } else if (negative) { return (a < 0 && b < 0); } } 

上面的方法逻辑上在所有分支中都有一个返回,但从技术上讲它没有。 我们希望Java编译器快速,因此不希望Java编译器在语义上分析代码。

 public boolean posNeg(int a, int b, boolean negative) { if (!negative) { return (a < 0 && b > 0) || (a > 0 && b < 0); } else { return (a < 0 && b < 0); } } 

上述方法在所有分支中都有返回。

 public boolean posNeg(int a, int b, boolean negative) { if (!negative) { return (a < 0 && b > 0) || (a > 0 && b < 0); } return (a < 0 && b < 0); } 

但是,正如您在上面所看到的,您甚至不需要else,因为如果代码到达第二个返回,那么否定肯定是假的,就好像它是真的一样,第一个返回将结束算法。

 public boolean posNeg(int a, int b, boolean negative) { return ((negative) && (a < 0 && b < 0)) || ((!negative) && (a < 0 && b > 0) || (a > 0 && b < 0)); } 

上述方法是单线。

 public boolean posNeg(int a, int b, boolean negative) { return ((negative) && (a < 0 && b < 0)) || ((!negative) && ((a < 0) == (b > 0))); } 

上述方法使用的事实是,在第二种情况下, a的积极性等于b的负性。