Intellij Idea IntelliJ抱怨“for语句不循环”?

23c0lvtd  于 2023-03-22  发布在  其他
关注(0)|答案(5)|浏览(264)

这是我的代码:

public enum Modification {
    NONE, SET, REMOVE;
}

boolean foo(List<S> sList){
    for (S s : sList) {
        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) {
    Modification modification = s.getModification();
    switch (modification) {
        case SET:
        case REMOVE:
            return true;
        case NONE:
            break;
    }
}

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

2cmtqfgy

2cmtqfgy1#

我刚刚在eclipse中尝试了这个方法,结果在switch语句上出现了一个编译器警告。
枚举常量NONE在修改时需要在此枚举开关中有一个对应的case标签
为了解决警告,我有以下选项。

  • 添加默认大小写
  • 添加缺少的case语句
  • 将@SuppressWarnings 'incomplete-switch'添加到foo()

如果我添加了缺少的case语句,那么警告就不再出现了。这和添加缺少的case语句会让你的错误警告从intellij中消失是一样的。
如果没有case NONE的语句,你只能看到两个case,这两个case都返回true。如果不知道Modification的结构和NONE的额外值,看起来这个循环在第一次迭代时只会返回true。
当然,编译器应该知道Modification的值比SET和REMOVE的值多,所以警告只是为了好的风格。基本上你的代码可以工作,但这里有一些改进方法。
我会选择添加一个default语句而不是缺少的case。这将是更多的未来证明,以防以后更多的值被添加到枚举中。

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

就我个人而言,我并不喜欢在switch语句上使用fall through。你在使代码简洁方面所获得的好处是你在易读性上失去了IMHO。如果有人后来来并在SET和REMOVE之间添加了一个case,它可能会引入一个bug。此外,在一个方法的中途有一个return语句也会引起问题。如果有人想在return之前添加一些代码,他们可能会错过所有的地方。如果这个方法非常简单,那么多重返回就可以了,但是你已经说过这是一个简化的例子,所以如果这个代码块很复杂,我会避免使用它。
如果你能够使用Java 8,那么这看起来是新的流API的完美用例。

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

gxwragnw2#

我假设这是你仅有的三种情况,对吗?,所以基本上它说你要击中前两个中的一个并立即返回true,因此不循环,只需添加一个default情况,一切都应该正常工作,这也是很好的实践。
基本上,它不能看到一个情况下,它不只是立即返回,而不迭代循环

ycggw6v2

ycggw6v23#

我会说这是一个假阳性。
第1个适应症:如果您通过调试器运行代码-并且列表中具有NONE修改的元素在具有其他修改的元素之前-它实际上将循环。
第二个适应症:当您查看生成的字节码时,它将switch语句转换为(某种程度上-它并不完全相同)

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

如果你把它放在你的代码中,IntelliJ不会抱怨。
第3种适应症:如果你在return之前加上一个额外的语句 *,警告就会消失,例如System.out.println();

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

看来你用丢失的箱子标签欺骗了检查,可以简单地忽略警告。

j0pj023g

j0pj023g4#

我认为IntelliJ的检查是错误的。我向JetBrains报告了
编辑:修好了

wz3gfoph

wz3gfoph5#

你的switch语句总是中断或返回。在第一种情况下,你什么都不做,也就是falls through。第二种情况下,return s导致switch和循环停止。在第三种情况下,你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的情况下,switch不会循环,因为return会中断循环并从函数返回一个值。break会中断switch循环,但会继续for循环。
根据OP的要求,提供额外的解释。
Falling through意味着下一个case将被执行,直到到达停止(breakreturn)。这使得以下代码片段等价:

case SET:
case REMOVE:
    return true;

等同于:

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

相关问题