使用流

时间:2015-09-18 14:50:04

标签: java

我有一个Java 8流的问题,试图在循环中继续下一个项目。我无法像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!
}

4 个答案:

答案 0 :(得分:183)

使用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语句的范围变得更加明显。

答案 1 :(得分:2)

将为从流中接收的每个元素评估要传递给forEach()的lambda。迭代本身在lambda的范围内是不可见的,因此你不能continue它就像forEach()是C预处理器宏一样。相反,您可以有条件地跳过其中的其余语句。

答案 2 :(得分:1)

另一种解决方案:使用倒置条件检查过滤器: 示例:

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

可以替换为

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

最直接的方法似乎是使用“返回”;虽然。

答案 3 :(得分:0)

您可以使用简单的if语句而不是继续。因此,您可以尝试使用

代替代码的方式
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;语句中的谓词相反,因此只需使用!(逻辑不是)。