java8新特性(二):stream流式编程详细介绍

发表时间:2023-04-13 15:37:09点击:2026

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。这是目前为止最大的一次对Java库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。Steam API极大得简化了集合操作。

下面简单介绍下stream的使用

我们先造一个List来测试一下,这个orderInfo有id,name和price三个属性

        List<OrderInfo> list = new ArrayList<>();
        OrderInfo orderInfo1 = new OrderInfo();
        orderInfo1.setId(1);
        orderInfo1.setName("apple");
        orderInfo1.setPrice(33.56);
        list.add(orderInfo1);
        OrderInfo orderInfo2 = new OrderInfo();
        orderInfo2.setId(2);
        orderInfo2.setName("huawei");
        orderInfo2.setPrice(1.2);
        list.add(orderInfo2);
        OrderInfo orderInfo3 = new OrderInfo();
        orderInfo3.setId(3);
        orderInfo3.setName("xiaomi");
        orderInfo3.setPrice(13.2);
        list.add(orderInfo3);

我现在要把list中每个orderInfo的name取出来,得到一个List,那么通常的做法是可以使用for循环

        List namesList = new ArrayList<>();
        for (OrderInfo info:list){
            namesList.add(info.getName());
        }

但是使用stream流之后,就可以使用一行代码搞定。类似地,也可以把id全部都取出来

        List<String> names = list.stream().map(orderInfo -> orderInfo.getName()).collect(Collectors.toList());
        List<Integer> ids = list.stream().map(orderInfo -> orderInfo.getId()).collect(Collectors.toList());
        System.out.println(names);
        System.out.println(ids);

我们运行一下,看看打印结果

[apple, huawei, xiaomi]
[1, 2, 3]

还可以用stream中的filter做筛选,筛选出符合条件的对象,比如,我要把list中name是apple的对象找出来

        List<OrderInfo> appleList = list.stream().filter(orderInfo -> orderInfo.getName().equals("apple")).collect(Collectors.toList());
        System.out.println("appleList:"+ JSON.toJSONString(appleList));

打印结果

appleList:[{"id":1,"name":"apple","price":33.56}]

还可以使用sum方法得出list中所有对象的某个属性的和,比如这个List订单列表的总价

        Double price = list.stream().mapToDouble(OrderInfo::getPrice).sum();
        System.out.println("price:"+price);

打印结果

price:47.96

以上介绍的stream的用法都是串行流,java8中还有并行流(Parallel Stream)。写法有两种

        list.stream().parallel();
        list.parallelStream();

之所以设计使用并行流处理来处理业务,是为了充分利用CPU资源以获取更好的性能,所以使用parallelStream理论上速度会更快。我们可以对比一下:

先定义一个list,放入1000个数

        List<Integer> linkedList =new LinkedList();
        for (int a = 1;a <=10000 ;a++) {
            linkedList.add(a);
        }

首先我们用传统的for循环遍历

        long start = System.currentTimeMillis();
        for (int a = 0; a < linkedList.size(); a++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("for循环遍历方式 : " + (System.currentTimeMillis() - start) + "ms");

然后我们用stream的串行流方式遍历

        linkedList.stream().forEach(r -> {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("stream串行遍历方式 : " + (System.currentTimeMillis() - start) + "ms");

最后我们用parallelStream并行流方式遍历

        linkedList.parallelStream().forEach(r -> {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("parallelStream并行遍历方式 : " + (System.currentTimeMillis() - start) + "ms");

一起运行,看看打印结果

for循环遍历方式 : 15358ms
stream串行遍历方式 : 30669ms
parallelStream并行遍历方式 : 32023ms

可以看到,前两种遍历方式的时间差不多,从0~15358ms,以及从15358ms~30669ms,但是并行流遍历的时间却特别短,30669ms~32023ms,非常快

最后多说一句,parallelStream虽然快,但是不要乱用,我们曾经遇到过在一个公共方法中使用了parallelStream来处理数据,结果很多入口都在调用这个方法,导致这个方法短时间内快速处理大量数据,疯狂占用CPU资源,CPU飙升导致服务器告警,系统卡顿。所以有些不是很重要,或者不需要那么及时处理的数据,可以不用parallelStream来处理。

当然,还有很多细节,这里就不逐一列举,根据以上几个例子,应该大致可以举一反三,自己去尝试探索和使用了

*原创文章,转载请注明出处