3

为什么这种方法一直告诉我它缺少返回语句?如果我删除 else 它告诉我返回 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;
        }
        
    }
4

2 回答 2

7

为什么这种方法一直告诉我它缺少返回语句?

因为有一种方法可以在for循环之后到达该点。考虑pass长度为零的情况。

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

for当且仅当以下至少一项为真时,基本语句才能正常完成:

  • 语句可达,for有条件表达式,条件表达式不是值为真的常量表达式(§15.29)。
  • 有一个可到达的 break 语句退出该for语句。

在您的示例中,第一个要求得到满足。因此,for循环可以正常完成。for因此在循环之后有一个返回点。因此return,此时需要声明。


请注意,可达性规则并不依赖于 Java 编译器足够聪明地分析应用程序的逻辑,它们也没有让编译器自行决定是否聪明。因此,有一些 Java 示例可以正式证明语句不可访问,但规则说它仍然是可访问的,并强制编译错误。

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

于 2020-11-29T09:05:02.937 回答
3

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

  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
    }

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

现在,由于@Stephen C 首先指出的用于确定语句的可达性的 Java 规则(并且已经很好地解释了,并且也是改进我的答案的灵感来源),因此在逻辑上涵盖了这三个场景将不要让你的代码编译干净。例如:

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 语句。为什么?因为根据上述规则,这个循环可以正常完成,因此return在 if 的末尾需要 a。但是,使用相同的语义相同的代码:

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

它编译得很好,即使在循环结束时没有返回语句。为什么?因为基于上述规则,我的循环不能正常完成了,因为它的条件表达式是true,关于它的更详细的信息可以在这里找到。公平地说,我的 IDE 一添加您的代码,就立即收到警告,即'for' statement does not loop.

总之,对于您的情况,您需要涵盖这三种情况,并在循环结束时有一个 return 语句,您可以在此处阅读更多信息或使用@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当您找到一个不是数字的字符或(在循环结束时)检查整个字符串之后,您才想要。如果字符串为空,我将返回!pass.isEmpty();以确保我们不会这样做。return true使用当前代码,我们涵盖了所有退出点,即:

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

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

另一个注意事项,使用 Java Streams,您可以将您的方法简化为:

public static boolean isDigit(String pass){
    return !pass.isEmpty() && pass.chars().allMatch(Character::isDigit);
}
于 2020-11-29T09:09:14.140 回答