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

我有一个问题与流的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!
}
151754 次浏览

使用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);
});
}

输出:

< p > < br > c < / p >

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

为什么会这样?

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

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

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


System.out.println(str);
}

... main方法确实需要被视为它自己独特的“方法”,完全独立于main方法,尽管它很方便地位于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语句的作用域变得更加明显。

你可以使用简单的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预处理器宏一样continue它。相反,您可以有条件地跳过其中的其余语句。

另一个解决方案:通过一个过滤器与你的反转条件: 例子:< / p >
if(subscribtion.isOnce() && subscribtion.isCalled()){
continue;
}

可以用

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

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