如果我将此代码的其他部分更改为else语句,则运行时没有任何问题,因此我知道如何使其运行。我有点困惑的是为什么当它处于当前形式时我得到一个丢失的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 && b > 0) || (a > 0 && b < 0);
}
else if (negative) {
return (a < 0 && b < 0);
}
}
public static void main (String[] args) throws java.lang.Exception
{
}
}
答案 0 :(得分:5)
当编译器看到else if
没有else
或尾随的return语句时,不能确定所有控制路径都会导致有效的return语句。
编译器有时可能很聪明,但在这种情况下它并不聪明(也不应该是)。
此行为在您的示例中很有用:在这种情况下,您绝对没有理由使用else if
。简单else
更容易阅读,更简洁,更不容易出错。
else
在这种情况下非常有表现力。这意味着&#34; 与if子句相反&#34;如果代码将来发生变化,情况仍然如此。
如果编译器允许,您当前的代码将更有可能包含和/或引入错误。
这是我如何重写方法体:
if (negative) {
return (a < 0 && b < 0);
}
else {
return (a < 0 && b > 0) || (a > 0 && b < 0);
}
一般情况下,您应该更喜欢if (negative)
而不是if (!negative)
,除非有令人信服的理由(即可读性)。
此外,很多人(包括我自己)试图将最简单的子句放在 if / else 语句中。使代码易于阅读是一件好事。
查看StephenC的答案,获得技术解释以及有关编译器为何如此行为的更多背景信息。
答案 1 :(得分:4)
其他问题从直观的角度解释了错误信息的含义。然而“编译器很聪明,但并不完美!”评论缺少重点。
实际上,Java编译器将您的示例调用为错误,因为Java语言规范要求将其称为错误。 Java编译器不允许对此“聪明”。
以下是JLS(对于Java 7 1 )实际上说的内容,以及它如何应用于错误示例的简化版本,然后是更正后的版本。
“如果声明一个方法具有返回类型,那么如果方法的主体可以正常完成(JLS 14.1),则会发生编译时错误。换句话说,一个方法返回类型必须仅使用提供值返回的return语句返回;不允许“放弃其主体的末尾”。“ - JLS 8.4.7
(阅读JLS 14.1了解“正常完成”的定义......)
决定“正常”完成是否可行的规则是JLS 14.21中的可达性规则。他们说:
- “如果if-then语句可以访问,则if-then语句可以正常完成。”
- “如果then语句可以正常完成或者else语句可以正常完成,则if-then-else语句可以正常完成。”
- “中断,继续,返回或抛出语句无法正常完成。”
醇>
(其中'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会说基本相同的东西,虽然章节数可能不同......
答案 2 :(得分:3)
if
=&gt; else if
=&gt; else
条件在哪里?
对于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);
答案 3 :(得分:3)
我想你已经知道第二个是多余的。
if (negative)
被解释为无上下文,这意味着编译器忽略已经处理过if(!negative)
。
答案 4 :(得分:2)
“else”括号中不需要“if(negative){}”
答案 5 :(得分:1)
你应该在所有分支机构都有回报。
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,因为如果代码到达第二个返回,那么否定肯定是假的,就好像它是真的一样,第一个返回将结束算法。 / p>
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
的否定性相等。