在Java 8中,在操作流中执行操作应该怎么做?

8
我有一个需求,要获取员工姓名包含“kumar”且年龄大于26岁的人数。我正在使用Java 8流迭代集合,并且能够找到符合上述条件的员工数量。
但是,在此期间,我需要打印员工详细信息。
这是我使用Java 8流的代码:
public static void main(String[] args) {

    List<Employee> empList = new ArrayList<>();

    empList.add(new Employee("john kumar", 25));
    empList.add(new Employee("raja", 28));
    empList.add(new Employee("hari kumar", 30));

    long count = empList.stream().filter(e -> e.getName().contains("kumar"))
                          .filter(e -> e.getAge() > 26).count();
    System.out.println(count);
}

传统方式:

public static void main(String[] args){
   List<Employee> empList = new ArrayList<>();

    empList.add(new Employee("john kumar", 25));
    empList.add(new Employee("raja", 28));
    empList.add(new Employee("hari kumar", 30));
    int count = 0;
    for (Employee employee : empList) {

        if(employee.getName().contains("kumar")){
            if(employee.getAge() > 26)
            {
                System.out.println("emp details :: " + employee.toString());
                count++;
            }
        }
    }
     System.out.println(count);
}

我希望能够使用流来实现与传统方式相同的打印操作。

当使用流时,如何在每次迭代中打印一条消息?

2个回答

23
您可以使用 Stream.peek(action) 方法来记录流中每个对象的信息:
long count = empList.stream().filter(e -> e.getName().contains("kumar"))
                      .filter(e -> e.getAge() > 26)
                      .peek(System.out::println)
                      .count();

peek 方法允许在流中每个元素被消耗时执行操作。该操作必须符合 Consumer 接口:接受类型为 T(流元素的类型)的单个参数 t,并返回 void


2
需要强调的是, peek 只对 已处理 的项执行操作,因此如果使用短路终端操作(如 findFirst),则不一定会处理所有项。此外,如果大小可预测(例如没有 filter),则 count() 可能会完全跳过处理。Java 9的实现具有这种优化... - Holger
有没有办法控制peek()方法?在生产环境中,我想禁用peek()方法的日志记录。一种方法是在代码中进行注释,但这需要编译代码和部署。还有其他的想法吗? - Krishna
1
@Krishna 的想法不是禁用 peek,而是使用一个日志框架,在开发和生产环境下记录不同的日志(基于配置文件)。看一下 log4j - Tunaki
1
@krishna 是的,如果你做类似 .peek(() -> logger.debug("Message")) 这样的事情,那么定义/使用的接口会知道为你调用 logger.isEnabled,你就不需要担心它了。请参见《Java 8 Lambdas》书的第42页。 - djangofan
如果你的操作不是一个消费者,你可以添加花括号.peek(() -> {doSomething();}) - ihebiheb

2

您的需求有些不明确,但这可能会有所帮助:
Lambda表达式(例如您的Predicate)可以有两种写法:
一种是不带括号的写法,如:e -> e.getAge() > 26

...filter(e -> {
              //do whatever you want to do with e here 

              return e -> e.getAge() > 26;
          })...

想要在将流传递到下一个操作之前打印流一的输出。 - Krishna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接