带有多个语句的Java 8 Lambda Stream forEach

时间:2015-06-30 05:45:03

标签: java lambda java-8

我仍然在学习Lambda,请原谅我如果我做错了什么

final Long tempId = 12345L;
List<Entry> updatedEntries = new LinkedList<>();

for (Entry entry : entryList) {
    entry.setTempId(tempId);
    updatedEntries.add(entityManager.update(entry, entry.getId()));
}

//entryList.stream().forEach(entry -> entry.setTempId(tempId));

似乎forEach只能为一个语句执行。它不会返回更新的流或函数以进一步处理。我可能完全选择了错误的一个。

有人可以指导我如何有效地做到这一点吗?

还有一个问题,

public void doSomething() throws Exception {
    for(Entry entry: entryList){
        if(entry.getA() == null){
            printA() throws Exception;
        }
        if(entry.getB() == null){
            printB() throws Exception;
        }
        if(entry.getC() == null){
            printC() throws Exception;
        }
    }
}
    //entryList.stream().filter(entry -> entry.getA() == null).forEach(entry -> printA()); something like this?

如何将其转换为Lambda表达式?

5 个答案:

答案 0 :(得分:47)

忘记与第一个代码段相关联。我根本不会使用forEach。由于您要将Stream的元素收集到List中,因此使用Stream结束collect处理会更有意义。然后,您需要peek才能设置ID。

List<Entry> updatedEntries = 
    entryList.stream()
             .peek(e -> e.setTempId(tempId))
             .collect (Collectors.toList());

对于第二个片段,forEach可以执行多个表达式,就像任何lambda表达式一样:

entryList.forEach(entry -> {
  if(entry.getA() == null){
    printA();
  }
  if(entry.getB() == null){
    printB();
  }
  if(entry.getC() == null){
    printC();
  }
});

但是(查看您的评论尝试),您无法在此方案中使用过滤器,因为您只会处理某些条目(例如,entry.getA() == null的条目)。 / p>

答案 1 :(得分:8)

List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
items.add("E");

//lambda
//Output : A,B,C,D,E
items.forEach(item->System.out.println(item));

//Output : C
items.forEach(item->{
    System.out.println(item);
    System.out.println(item.toLowerCase());
  }
});

答案 2 :(得分:6)

在第一种情况下,替换为多行forEach,您可以使用peek流操作:

entryList.stream()
         .peek(entry -> entry.setTempId(tempId))
         .forEach(updatedEntries.add(entityManager.update(entry, entry.getId())));

在第二种情况下,我建议将循环体提取到单独的方法,并使用方法引用通过forEach调用它。即使没有lambdas,它也会使你的代码更加清晰,因为循环体是独立的算法,它处理单个条目,所以它在其他地方也很有用,可以单独测试。

编辑问题后更新。如果您检查了异常,那么您有两个选择:将它们更改为未选中的或者根本不在这段代码中使用lambdas / streams。

答案 3 :(得分:3)

您不必将多个操作塞入一个流/ lambda。考虑将它们分成2个语句(使用静态导入toList()):

entryList.forEach(e->e.setTempId(tempId));

List<Entry> updatedEntries = entryList.stream()
  .map(e->entityManager.update(entry, entry.getId()))
  .collect(toList());

答案 4 :(得分:0)

我的首选方法是将 java.util.function.Consumer<?>andThen(...) 连接起来。

应用于你的例子,可以写成:

entryList.stream()
  .forEach(
    ((Consumer<Entry>) entry -> entry.setTempId(tempId))
    .andThen(entry -> updatedEntries.add(entityManager.update(entry, entry.getId())))
  );

这样看,读起来不太好……但是您可以将 2 个使用者移动到本地函数变量中,它会变得像:

Consumer<Entry> c1 = entry -> entry.setTempId(tempId);
Consumer<Entry> c2 = entry -> updatedEntries.add(entityManager.update(entry, entry.getId()));
entryList.stream().forEach(c1.andThen(c2));

奖金

你可以像这样编写你的消费者组合:

public static <T> Consumer<T> combine(Consumer<? super T>... consumers){
  return (T t) ->   Arrays.stream(consumers).forEach(c -> c.accept(t));
}

它允许重写上面的例子:

entryList.stream()
  .forEach(combine(
    entry -> entry.setTempId(tempId),
    entry -> updatedEntries.add(entityManager.update(entry, entry.getId()))));

希望Consumer类有一个方法可以组合多个相同类型的消费者,也许这个combine已经存在于某处而我不知道,所以我邀请您搜索?< /p>