为什么此代码缺少返回语句错误?
如果我将此代码的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中的可达性规则。 他们说:
- “if if-then语句可以正常完成,如果它可以访问的话。”
- “如果then语句可以正常完成或者else语句可以正常完成,那么if-then-else语句可以正常完成。”
- “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
的负性。