Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this code have a missing return statement error?

Tags:

java

If I change the else if portion of this code to an else statement it runs without any problems so I get how to make it run. What I'm a little confused about is why I get a missing return statement error when it is in its current form. My return is dependent on the value of the boolean variable of negative. I covered the true and false states, isn't that good enough to cover everything?

Or is it that I always have to have a return statement within an else or to add a meaningless return true to the bottom of my function for the compiler to accept my code as covering every case?

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
    {
    }
}
like image 625
jay Avatar asked Mar 30 '14 00:03

jay


2 Answers

When the compiler sees else if without an else or a trailing return statement, it cannot be certain that all control paths will lead to a valid return statement.

The compiler can be smart at times, but it can't be smart in this situation (nor should it be).

This behavior is helpful in your example: there's absolutely no reason for you to use an else if in this situation. A simple else is easier to read, more concise, and less error prone.

An else is very expressive in this case. It means "the opposite of the if clause" which will still be the case if the code changes in the future.

Your current code would be more likely to contain and/or introduce a bug if the compiler allowed it.

Here's how I would rewrite the method body:

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

In general you should prefer if (negative) over if (!negative) unless there's a compelling reason (ie readability) to do otherwise.

Also, a lot of people (including myself) try to put the most simple clause first in an if/else statement. Making your code easy to read is a good thing.

Check out StephenC's answer for a technical explanation and more background about why the compiler behaves this way.

like image 61
jahroy Avatar answered Nov 02 '22 23:11

jahroy


Other questions have explained what the error message means from an intuitive perspective. However the "The compiler is smart, but not perfect!" comment is missing the point.

In fact, the Java compiler is calling your example an error because the Java Language Specification requires it to call it an error. The Java compiler is not permitted to be "smart" about this.


Here is what the JLS (for Java 71) actually says, and how it applies to a simplified version of the incorrect example, and then a corrected version.

"If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (JLS 14.1). In other words, a method with a return type must return only by using a return statement that provides a value return; it is not allowed to "drop off the end of its body". " - JLS 8.4.7

(Read JLS 14.1 for the definition of "normal completion" ...)

And the rules for deciding whether a "normal" completion is possible are the reachability rules in JLS 14.21. And they say:

  1. "An if-then statement can complete normally iff it is reachable."
  2. "An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally."
  3. "A break, continue, return, or throw statement cannot complete normally."

(Where 'iff' means "if and only if" ...)

Consider a simplified version of the example:

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

In this example, the else-statement is an if-then which can complete normally by rule #1. Therefore, by rule #2, the if-then-else statement can also complete normally. But that is a compilation error, because JLS 8.4.7 says that a method with a return type cannot complete normally.

But if you change the example to this ...

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

Now by rule #3, both the if-statement and the else-statement cannot complete normally. So by rule #2, the entire if-then-else cannot complete normally. That is what it required by JLS 8.4.7 ... therefore no compilation error.

1 - The Java 8 JLS will say essentially the same thing, though the section numbers may be different ...

like image 40
Stephen C Avatar answered Nov 02 '22 23:11

Stephen C