Why is it giving me a return missing error?

153 views Asked by At

Why does this method keep telling me it's missing a return statement ? and if I remove the else it tells me the return true isn't reachable. Thanks in advance for your help !

 public static boolean Digit(String pass){
        for (int i=0; i < pass.length(); i++ ){
            if (!Character.isDigit(pass.charAt(i))) {
                System.out.println("Must contain digits");
                return false;
            }
            else
                return true;
        }
        
    }
2

There are 2 answers

1
dreamcrash On BEST ANSWER

It is complaining because you are missing a return at the end of the loop. Your method can exit in three different scenarios, namely:

  1. when the string pass is not empty and the first character is not a digit;
  2. when the string pass is not empty and the first character is a digit;
  3. when the string is empty!.

in code:

public static boolean Digit(String pass){
       for (int i=0; i < pass.length(); i++ ){
           if (!Character.isDigit(pass.charAt(i))) {
               System.out.println("Must contain digits");
               return false; // <--- can exit here
            }
            else
               return true; // <-- can exit here
        }
      // <-- can exit here if the string pass is empty
    }

You are covering the first two cases, but not the third (i.e., when the string is empty).

Now, because of the Java rules "for determining the reachability of a statement" as @Stephen C have pointed out first (and have explained quite well, and was source of inspiration to improve my answer as well) logically covering the three scenarios alone will not make your code compile clean. For instance:

public static boolean Digit(String pass){
    if(pass.isEmpty())
        return false;

    for (int i=0; i < pass.length(); i++ ){
        if (!Character.isDigit(pass.charAt(i))) {
            System.out.println("Must contain digits");
            return false;
        }
        else
            return true;
    }
}

in the code above all possible exit points are cover, nonetheless, my IDE still complains about missing the return statement. Why? because based on the aforementioned rules this loop can complete normally, and consequently needs a return at the end of if. However, with the same semantically identical code:

  public static boolean Digit(String pass){
        if(pass.isEmpty())
            return false;

        for (int i = 0; true; i++ ){
            if (!Character.isDigit(pass.charAt(i))) {
                System.out.println("Must contain digits");
                return false;
            }
            else
                return true;
        }
    }

it compiles fine, even without the returning statement at the end of the loop. Why? because based on the aforementioned rules my loop cannot complete normally anymore, since its condition expression is true, more detailed information about it can be found here. In all fairness to my IDE, as soon as I added your code I got the immediately warned that the 'for' statement does not loop.

In summary, for your case you need to cover the three scenario, and have a return statement at the end of the loop, you can read more about here or with @Stephen C answer which breaks it down very nicely.

Beside all this, your method is not doing what you want. You are only comparing the first digit of the string, but you should check the entire string, like:

 public static boolean Digit(String pass){
        for (int i=0; i < pass.length(); i++ ){
            if (!Character.isDigit(pass.charAt(i))) {
                System.out.println("Must contain digits");
                return false;
            }
        }
        return !pass.isEmpty();
    }

You want to only return when either you find a character that is not a digit or (at the end of the loop) after the entire string has been checked. I am returning !pass.isEmpty(); to ensure that we do not return true if the string is empty. With the current code we cover all the exit points, namely:

  1. if the string contains only digits you will reach the statement return !pass.isEmpty();, and consequently return true;
  2. if the string contains at least a non digit, you will reach return false;;
  3. If the string is empty you will reach return !pass.isEmpty();, and consequently return false.

A side note, you should change the name of your method from Digit to isAllDigits, the latter is more explicit that the former.

Another side note, with Java Streams you can simplified your method to only:

public static boolean isDigit(String pass){
    return !pass.isEmpty() && pass.chars().allMatch(Character::isDigit);
}
0
Stephen C On

Why does this method keep telling me it's missing a return statement ?

Because there is a way to reach the point after the for loop. Consider the case where pass has length zero.

More generally, the rules for determining the reachability of a statement (or point in the code) are set out in JLS 14.22. The relevant rule for a simple for loop is as follows:

A basic for statement can complete normally if and only if at least one of the following is true:

  • The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression (ยง15.29) with value true.
  • There is a reachable break statement that exits the for statement.

In your example, the first requirement is satisfied. Therefore, the for loop can complete normally. Therefore there is a return point after the for loop. Therefore a return statement is required at that point.


Note that the reachability rules do not depend on the Java compiler being clever enough to analyze your application's logic, and they don't give the compiler the discretion to be smart about it. So there are Java examples where one can formally prove that a statement is not reachable, and yet the rules say it is reachable nonetheless, and mandate a compilation error.

(So in your example, the compiler does not need to reason that your code doesn't take account of zero length strings. That's "human level" reasoning.)