我有一个问题与流的Java 8 foreach试图移动下一个项目在循环。我不能设置命令像继续;,只有返回;工作,但在这种情况下,您将退出循环。我需要继续循环中的下一个项目。我该怎么做呢?

例子(工作):

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
            filteredLines = lines.filter(...).foreach(line -> {
           ...
           if(...)
              continue; // this command doesn't working here
    });
}

例子(工作):

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
    filteredLines = lines.filter(...).collect(Collectors.toList());
}

for(String filteredLine : filteredLines){
   ...
   if(...)
      continue; // it's working!
}

使用返回;会工作得很好。它不会阻止整个循环的完成。它只会停止执行forEach循环的当前迭代。

试试下面的小程序:

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");

    stringList.stream().forEach(str -> {
        if (str.equals("b")) return; // only skips this iteration.

        System.out.println(str);
    });
}

输出:

一个 c

注意如何返回;在b迭代中执行,但是在接下来的迭代中打印c也很好。

为什么会这样?

这种行为起初看起来不太直观的原因是因为我们习惯了return语句中断整个方法的执行。所以在这种情况下,我们期望主方法的执行作为一个整体被停止。

然而,需要理解的是lambda表达式,例如:

str -> {
    if (str.equals("b")) return;

    System.out.println(str);
}

... Really需要被视为它自己独特的“方法”,完全独立于主方法,尽管它很方便地位于主方法中。实际上,return语句只是停止了lambda表达式的执行。

第二件需要理解的事情是:

stringList.stream().forEach()

... 实际上只是一个普通的循环,为每次迭代执行lambda表达式。

考虑到这两点,上面的代码可以用以下等价的方式重写(仅用于教学目的):

public static void main(String[] args) {
    ArrayList<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");

    for(String s : stringList) {
        lambdaExpressionEquivalent(s);
    }
}

private static void lambdaExpressionEquivalent(String str) {
    if (str.equals("b")) {
        return;
    }

    System.out.println(str);
}

使用这个“不那么神奇”的代码等效物,return语句的作用域变得更加明显。


你可以使用一个简单的if语句来代替continue。所以,你可以尝试以下方法来代替你的代码:

try(Stream<String> lines = Files.lines(path, StandardCharsets.ISO_8859_1)){
            filteredLines = lines.filter(...).foreach(line -> {
           ...
           if(!...) {
              // Code you want to run
           }
           // Once the code runs, it will continue anyway
    });
}

if语句中的谓词与if(pred) continue语句中的谓词相反;语句,所以使用!(逻辑)。


传递给forEach()的lambda值将根据从流接收到的每个元素进行计算。迭代本身在lambda范围内是不可见的,因此您不能将forEach()当作C预处理器宏来继续它。相反,您可以有条件地跳过其中的其余语句。


另一个解决方案:通过一个过滤器与你的反向条件: 例子:

if(subscribtion.isOnce() && subscribtion.isCalled()){
                continue;
}

可以用

.filter(s -> !(s.isOnce() && s.isCalled()))

不过,最直接的方法似乎是使用“return;”。