为什么它给我一个 return 缺失错误?

Why is it giving me a return missing error?

为什么这个方法总是告诉我它缺少 return 语句?如果我删除 else,它会告诉我无法访问 return true。预先感谢您的帮助!

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

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

因为在for循环之后有办法到达那个点。考虑 pass 的长度为零的情况。

更一般地说,JLS 14.22 中列出了确定语句(或代码中的点)可达性的规则。一个简单的for循环的相关规则如下:

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.

在您的示例中,满足了第一个要求。因此,for循环可以正常完成。因此在 for 循环之后有一个 return 点。因此,此时需要 return 语句。


请注意,可达性规则不依赖于 Java 编译器是否足够聪明来分析您的应用程序的逻辑,并且它们不会赋予编译器聪明的判断力。因此,有 Java 个示例,其中可以 正式证明 一个语句是不可访问的,但规则说它仍然是可访问的,并要求编译错误。

(因此在您的示例中,编译器不需要推断您的代码没有考虑零长度字符串。这是“人类水平”的推理。)

它在抱怨,因为你在循环结束时缺少一个 return。您的方法可以在三种不同的情况下退出,即:

  1. 当字符串pass不为空且首字符不为 一个数字;
  2. 当字符串pass不为空且首字符为数字时;
  3. 当字符串为空时!.

在代码中:

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
    }

您涵盖了前两种情况,但没有涵盖第三种情况(,当字符串为空时)。

现在,由于 Java 规则 "for determining the reachability of a statement" 正如@Stephen C 首先指出的(并且已经解释得很好,并且改进我的答案的灵感来源)逻辑上涵盖三个场景 单独 不会使您的代码编译干净。例如:

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

在上面的代码中,所有可能的退出点都被覆盖了,尽管如此,我的 IDE 仍然抱怨缺少 return 语句。为什么?因为根据上述规则,这个循环可以正常完成,因此需要在if的末尾添加一个return。但是,使用相同的语义相同代码:

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

它编译得很好,即使在循环结束时没有 returning 语句。为什么?因为根据上述规则,我的循环无法再正常完成,因为它的条件表达式是 true,可以找到有关它的更多详细信息 here。平心而论,我的 IDE,只要我添加了您的代码,我就立即收到警告 'for' statement does not loop.

总而言之,对于您的情况,您需要涵盖三种情况,并在循环结束时有一个 return 语句,您可以阅读有关 here 或@Stephen C 的更多信息答案很好地分解了它。

除此之外,您的方法并没有按照您的意愿行事。您只比较字符串的第一个数字,但您应该检查整个字符串,例如:

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

您只想 return 当您发现一个不是数字的字符或(在循环结束时)检查了整个字符串后。我正在 returning !pass.isEmpty(); 以确保我们不会 return true 如果字符串为空。使用当前代码,我们涵盖了所有出口点,即:

  1. 如果字符串仅包含数字,您将到达语句 return !pass.isEmpty();,因此 return true
  2. 如果字符串至少包含一个非数字,你将达到return false;;
  3. 如果字符串为空,您将到达 return !pass.isEmpty();,因此 return false

附带说明,您应该将方法的名称从 Digit 更改为 isAllDigits,后者比前者更明确。

另一个旁注,使用 Java Streams,您可以将方法简化为:

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