Search code examples
javaunreachable-statement

Why is it giving me a return missing error?


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;
        }
        
    }

Solution

  • 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);
    }