在流中使用 Java 8 foreach 循环移至下一项

问题描述

使用return;会很好。它不会阻止完整循环的完成。它只会停止执行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);
    });
}

输出

一个 _

注意迭代return;是如何执行的b,但是c在接下来的迭代中打印就好了。

为什么这行得通?

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

但是,需要理解的是一个lambda表达式,比如:

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

    System.out.println(str);
}

…确实需要将其视为自己独特的“方法”,与main方法完全分开,尽管它位于其中很方便。所以实际上,该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语句的范围变得更加明显。

解决方法

我对 Java 8 foreach 流尝试移动到循环中的下一个项目时遇到问题。我不能像
一样设置命令continue;,只能return;工作,但在这种情况下你会退出循环。我需要继续循环中的下一个项目。我怎样才能做到这一点?

示例(不工作):

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