为啥它给我一个返回丢失错误?

Posted

技术标签:

【中文标题】为啥它给我一个返回丢失错误?【英文标题】:Why is it giving me a return missing error?为什么它给我一个返回丢失错误? 【发布时间】:2021-03-11 11:35:39 【问题描述】:

为什么这个方法总是告诉我它缺少一个返回语句?如果我删除 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;
        
        
    

【问题讨论】:

【参考方案1】:

为什么这个方法总是告诉我它缺少一个返回语句?

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

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

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

for 语句可达,存在条件表达式,且条件表达式不是值为 true 的常量表达式(第 15.29 节)。 有一个可到达的 break 语句退出 for 语句。

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


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

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

【讨论】:

【参考方案2】:

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

    当字符串pass不为空且首字符不为 一个数字; 当字符串pass不为空且首字符为数字时; 当字符串为空时!。

在代码中:

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;
        
    

它编译得很好,即使在循环结束时没有返回语句。为什么?因为基于上述规则,我的循环无法正常完成,因为它的条件表达式是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。如果字符串为空,我将返回 !pass.isEmpty(); 以确保我们不会 return true。使用当前代码,我们涵盖了所有退出点,即:

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

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

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

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

【讨论】:

感谢您的输入!我只是忘了把循环的括号加起来

以上是关于为啥它给我一个返回丢失错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥地理定位给我的当前位置错误的导航器当前位置方法?

% url % 给我 NoReverseMatch 错误,而 reverse() 返回 url 就好了。为啥?

Mapbox:我想使用 Locationengine 来获取用户的当前位置,但它给我一个错误

为啥我会收到“CSRF 令牌丢失或不正确”错误?

为啥 LEFT(Datetime,1) 给我“J”?

我有一个错误,我不确定它为啥不工作(线程)