关于stream.foreach()和stream.peek()的区别解析

时间:2021-08-20 19:10:14

改思考来源于日常工作中,特记此心得。

 

思考:如何快速将list中的每个item内部属性值改变并进行其他流体操作呢?

下面做个测试:如何在list中根据某个属性的最小值取出该对象

 

1:随便新建一个测试bean:

 

关于stream.foreach()和stream.peek()的区别解析关于stream.foreach()和stream.peek()的区别解析
 1 package com.dev.model;
 2 
 3 import javax.persistence.*;
 4 
 5 public class Aopi {
 6     /**
 7      * id
 8      */
 9     @Id
10     @GeneratedValue(strategy = GenerationType.IDENTITY)
11     private Integer id;
12 
13     /**
14      * 姓名
15      */
16     private String name;
17 
18     /**
19      * 年龄
20      */
21     private Integer age;
22 
23     /**
24      * 获取id
25      *
26      * @return id - id
27      */
28     public Integer getId() {
29         return id;
30     }
31 
32     /**
33      * 设置id
34      *
35      * @param id id
36      */
37     public void setId(Integer id) {
38         this.id = id;
39     }
40 
41     /**
42      * 获取姓名
43      *
44      * @return name - 姓名
45      */
46     public String getName() {
47         return name;
48     }
49 
50     /**
51      * 设置姓名
52      *
53      * @param name 姓名
54      */
55     public void setName(String name) {
56         this.name = name;
57     }
58 
59     /**
60      * 获取年龄
61      *
62      * @return age - 年龄
63      */
64     public Integer getAge() {
65         return age;
66     }
67 
68     /**
69      * 设置年龄
70      *
71      * @param age 年龄
72      */
73     public void setAge(Integer age) {
74         this.age = age;
75     }
76 
77     public Aopi(String name, Integer age) {
78         this.name = name;
79         this.age = age;
80     }
81 
82     public Aopi() {
83     }
84 
85     @Override
86     public String toString() {
87         return "Aopi{" +
88                 "id=" + id +
89                 ", name='" + name + '\'' +
90                 ", age=" + age +
91                 '}';
92     }
93 }
View Code

 

 

 

2:新建一个单元测试:

 

    @Test
    public void test01() {
        List<Aopi> aopiList = Lists.newArrayList();

        Aopi aopi = new Aopi("1", 1);
        Aopi aop2 = new Aopi("2", 2);
        Aopi aop3 = new Aopi("3", 3);
        Aopi aop4 = new Aopi("4", 4);

        aopiList.addAll(Arrays.asList(aopi, aop2, aop3, aop4));

        //第一种方式
        aopiList.forEach(item -> item.setName(item.getName() + "_test"));
        System.out.println(
                aopiList.stream().min((o1, o2) -> {
                    if (Objects.equals(o1.getAge(), o2.getAge()))
                        return 0;
                    return o1.getAge() > o2.getAge() ? 1 : -1;
                }).get().toString()
        );

        System.out.println("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");

        //第二种方式
        System.out.println(
                aopiList.stream().peek(item -> item.setName(item.getName() + "_test")).min((o1, o2) -> {
                    if (Objects.equals(o1.getAge(), o2.getAge()))
                        return 0;
                    return o1.getAge() > o2.getAge() ? 1 : -1;
                }).get().toString()
        );

    }

 

notice1:测试第一种方式注释掉第二种,反之亦如此

notice2:list.stream().foreach  ->  list.foreach()

 

 

3:看测试结果:

第一种测试结果:

关于stream.foreach()和stream.peek()的区别解析

 

第二种测试结果:

关于stream.foreach()和stream.peek()的区别解析

 

 

结论:

(1):使用stream.foreach也可以更改list中的每个item的内部属性值等等,但是要进行“二次流处理”,才能得到list中最小的item(根据age筛选)

(2):stream.peek比stream.foreach()可以跟直接拿到最小的item(根据age筛选)

 

原因:

(1):stream.foreach的操作是void的,除了更改属性值还可以进行其他操作等。因此要做“二次流处理”。

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

(1):stream.peek的操作是返回一个新的stream的,且设计的初衷是用来debug调试的,因此使用steam.peek()必须对流进行一次处理再产生一个新的stream。

    /**
     * Returns a stream consisting of the elements of this stream, additionally
     * performing the provided action on each element as elements are consumed
     * from the resulting stream.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * <p>For parallel stream pipelines, the action may be called at
     * whatever time and in whatever thread the element is made available by the
     * upstream operation.  If the action modifies shared state,
     * it is responsible for providing the required synchronization.
     *
     * @apiNote This method exists mainly to support debugging, where you want
     * to see the elements as they flow past a certain point in a pipeline:
     * <pre>{@code
     *     Stream.of("one", "two", "three", "four")
     *         .filter(e -> e.length() > 3)
     *         .peek(e -> System.out.println("Filtered value: " + e))
     *         .map(String::toUpperCase)
     *         .peek(e -> System.out.println("Mapped value: " + e))
     *         .collect(Collectors.toList());
     * }</pre>
     *
     * @param action a <a href="package-summary.html#NonInterference">
     *                 non-interfering</a> action to perform on the elements as
     *                 they are consumed from the stream
     * @return the new stream
     */
    Stream<T> peek(Consumer<? super T> action);

 

bye~^_^