【问题标题】:Java 8 Lambda Stream forEach with multiple statements具有多个语句的 Java 8 Lambda Stream forEach
【发布时间】:2015-06-30 05:45:03
【问题描述】:

我还在学习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 表达式?

【问题讨论】:

    标签: java lambda java-8


    【解决方案1】:

    忘记涉及到第一个代码sn-p。我根本不会使用forEach。由于您将Stream 的元素收集到List 中,因此使用collect 结束Stream 处理会更有意义。然后你需要peek 来设置ID。

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

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

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

    但是(查看您评论的尝试),您不能在这种情况下使用过滤器,因为如果您这样做,您只会处理一些条目(例如,entry.getA() == null 的条目)。

    【讨论】:

    【解决方案2】:
    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());
      }
    });
    

    【讨论】:

    • 这似乎是无效的语法。最后不是多了一个}吗?
    【解决方案3】:

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

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

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

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

    【讨论】:

    • 使用peek有什么好处。这个功能我没试过
    • @Reddy 在这种情况下我看不到真正的优势,因为您可以在peekforEach 中执行setTempId 调用,并且行为将相似。但是,如果您根本不使用forEach,而是使用collect 来生成输出列表(请参阅我更新的答案),则需要peek 才能调用setTempId。跨度>
    • 请记住peek mainly should be used in debug purpose。对流式数据应用副作用时使用forEach
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      我首选的方法是将java.util.function.Consumer&lt;?&gt;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 已经存在于某个地方并且我不知道它,所以我邀请你搜索?

      【讨论】:

        猜你喜欢
        • 2021-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-24
        • 1970-01-01
        • 2019-10-04
        • 1970-01-01
        • 2018-09-17
        相关资源
        最近更新 更多