【问题标题】:IntelliJ complaining "for statement does not loop"?IntelliJ 抱怨“for 语句不循环”?
【发布时间】:2016-03-30 08:53:17
【问题描述】:

这是我的代码:

public enum Modification {
    NONE, SET, REMOVE;
}

boolean foo(){
    for (S s : sList) {
        final Modification modification = s.getModification();
        switch (modification) {
            case SET:
            case REMOVE:
                return true;
            /*
            case NONE:
                break;
            */
        }
    }
    return false;
}

当代码如上所示时,IntelliJ 会说:

'for' 语句不会少循环... () 报告任何 for 实例, while 和 do 语句,其主体最多保证执行 一次。通常,这表明存在错误。

只有我做出以下更改,IntelliJ 才会高兴:

for (S s : sList) {
    final Modification modification = s.getModification();
    switch (modification) {
        case SET:
        case REMOVE:
            return true;
        case NONE:
            break;
    }
}

如果 case NONE: 未包含在 switch 语句中,为什么我的 for 循环不循环?

【问题讨论】:

  • 还有更多 IDE '需要'默认选项。我的猜测:IntelliJ 将您实现的所有选项视为唯一可能的选项,并且它们都在第一次迭代时执行返回。
  • 我认为这是您仅有的三种情况,对吗?所以基本上它是说您将要击中前两种中的一种并立即返回 true,因此不循环,只需添加 default case跨度>
  • @AlexHall 和 case NONE 会重复多次,请再次检查。
  • @KorayTugay @Kiltos 它只会在return 语句未执行时循环,而没有case NONEreturn 不会执行的唯一方法是前两种情况不执行与开关匹配,这可能发生。
  • 是的,它确实循环了,Intellij 错了。

标签: java for-loop intellij-idea


【解决方案1】:

我刚刚在 Eclipse 中尝试过,结果你在 switch 语句上得到了编译器警告。

枚举常量NONE在这个枚举开关上需要一个对应的case标签修改

为了解决警告,我提供了以下选项。

  • 添加默认情况
  • 添加缺少的案例陈述
  • 将 @SuppressWarnings 'incomplete-switch' 添加到 foo()

如果我添加缺少的 case 语句,则不再出现警告。与添加丢失的情况相同,会使您的 error 警告从 intellij 中消失。

如果没有 case NONE 语句,您只能看到两种情况,这两种情况都返回 true。在不知道 Modification 的结构和 NONE 的额外值的情况下,看起来这个循环只会在循环的第一次迭代时返回 true。

当然,编译器实际上应该知道 Modification 的值比 SET 和 REMOVE 更多,所以警告只是为了更好的风格。基本上你的代码可以工作,但这里是如何改进它。

我会选择添加默认语句而不是缺少的情况。如果稍后将更多值添加到枚举中,这将是更多的未来证明。例如

switch (modification) 
{
  case SET:
  case REMOVE:
    return true;
  default:
    break;
}

就我个人而言,我不喜欢在 switch 语句中使用 fall through。您在使代码简洁中获得的东西会在易读性恕我直言中丢失。如果后来有人来并在 SET 和 REMOVE 之间添加了一个案例,它可能会引入一个错误。此外,在方法的中途有一个 return 语句也会导致问题。如果有人想在返回之前添加一些代码,他们可能会错过所有的地方。如果方法很简单,那么多次返回就可以了,但是你已经说过这是一个简化的例子,所以如果这个代码块很复杂,我会避免它。

如果您能够使用 Java 8,那么这似乎是新流 API 的完美用例。像下面这样的东西应该可以工作。

return sList.stream().anyMatch(
  modification -> (modification==Modification.SET || modification==Modification.REMOVE)
);

【讨论】:

  • 最佳答案:)
  • 顺便说一句,这不是错误信息,而是警告;或者,准确地说,这就是 IntelliJ 所说的“检查”,当您将光标放在 for 关键字上时就会出现这种情况。因此该消息具有误导性,因为它应该给出关于不完整切换的警告,但无论如何使用流的功能样式要好得多。
  • 嗯,好的,感谢您的澄清,这个问题并没有说明它是警告还是错误,所以我一定只是假设这是一个错误。
【解决方案2】:

我假设这是您仅有的三个案例,对吗?所以基本上它说您将要击中前两个案例中的一个并立即返回 true,因此不循环,只需添加一个 default 案例,一切都应该正常,顺便说一句,这也是一种好习惯。

基本上它看不到在不迭代循环的情况下它不会立即返回的情况

【讨论】:

    【解决方案3】:

    我会说这是误报。

    第一个迹象: 如果您通过调试器运行代码 - 并且列表中的元素在具有其他修改的元素之前具有 NONE 修改 - 它实际上会循环。

    第二个迹象: 当您查看生成的字节码时,它会将 switch 语句转换为(有点 - 它完全相同相同)

    for (S s : sList) {
        Modification modification = s.getModification();
            switch (modification.ordinal()) {
                case 1:
                case 2:
                    return true;
        }
    }
    

    如果你把它放在你的代码中,IntelliJ 不会抱怨。

    第三个迹象: 如果您在返回之前添加附加语句,警告就会消失,即System.out.println();

     switch (modification) {
         case SET:
         case REMOVE:
           System.out.println()
           return true;
    

    您似乎用缺少的案例标签欺骗了检查,可以简单地忽略警告。

    【讨论】:

      【解决方案4】:

      我认为 IntelliJ 的检查是错误的。我举报给JetBrains

      编辑:已修复

      【讨论】:

        【解决方案5】:

        您的开关盒总是损坏或返回。在第一种情况下,您什么也不做,也就是 falls through。第二种情况returns 导致开关和循环都停止。在第三种情况下,您 break 导致它停止的 switch 语句。然而,它并没有停止 for 循环(也就是它不断迭代)。

        SET 案例添加特定功能或更改您在REMOVENONE 案例中的行为。

        public enum Modification {
            NONE, SET, REMOVE;
        }
        
        boolean foo(){
            for (S s : sList) {
                final Modification modification = s.getModification();
                switch (modification) {
                    case SET:
                       // This case falls through to the REMOVE case
                    case REMOVE:
                        return true; // This statement stops the switch, loop and returns true
                    case NONE:
                        break; // This statement stops the switch and continues the loop.
                }
            }
            return false;
        }
        

        如果没有NONE 情况,您的开关不会循环,因为return 会中断循环并从函数返回一个值。 break 中断 switch 循环,但继续 for 循环。


        应 OP 的要求,提供额外解释。

        Falling through 意味着将执行下一个案例,直到达到停止(breakreturn)。这使得以下代码 sn-ps 等效:

        case SET:
        case REMOVE:
            return true;
        

        等同于:

        case SET:
            return true;
        case REMOVE:
            return true;
        

        【讨论】:

        • @rustedbrain 这是怎么回事? OP 的代码确实循环了很多次,即使 IntelliJ 说它没有。
        • @KlitosKyriacou 如果您阅读了整个问题和我的回答,您会发现这正是我要说的。
        • 对不起,我好像误会了你。您说“没有 NONE 案例,您的开关不会循环”,但实际上它确实在没有 NONE 案例的情况下循环。
        • @ldebruijn 就是这样!它将执行 10 次。所以IDE错了。
        • 是的。因此,当它作为参数传递时,casesswitch 都不匹配时,它将循环。但 IDE 警告它不会。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        • 2021-02-12
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 2013-02-06
        相关资源
        最近更新 更多