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

时间:2014-03-30 00:24:50

标签: java

如果我将此代码的其他部分更改为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
    {
    }
}

6 个答案:

答案 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中的可达性规则。他们说:

  
      
  1. “如果if-then语句可以访问,则if-then语句可以正常完成。”
  2.   
  3. “如果then语句可以正常完成或者else语句可以正常完成,则if-then-else语句可以正常完成。”
  4.   
  5. “中断,继续,返回或抛出语句无法正常完成。”
  6.   

(其中'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的否定性相等。