本篇主要讲述Stream的使用姿势,以及Stream流一通操作后,没有得到预期效果,“假失效的问题”。刚开始使用Stream流时很有可能遇到以上问题,其实这就是我开发中遇到过的问题。然后百度,谷歌无果,只好自己动手了!

Stream流是JDK8的新特性,通常用于处理集合。先抛出我遇到的问题,使用Stream的sorted方法时,处理后的集合跟处理前的集合是‘一致的’。就像这样:

public class StreamSortTest {
    // 定义一个商品集合
    private static List<Commodity> commodities = new ArrayList<>();

    // 初始化商品集合
    static {
        commodities.add(new Commodity("312324", "商品4", "4"));
        commodities.add(new Commodity("312321", "商品1", "1"));
        commodities.add(new Commodity("312325", "商品5", "5"));
        commodities.add(new Commodity("312323", "商品3", "3"));
        commodities.add(new Commodity("312322", "商品2", "2"));
    }

    // 测试(使用Stream的sorted方法对商品进行排序)
    public static void main(String[] args) {
        System.out.println("排序前:");
        for (Commodity commodity : commodities) {
            System.out.println(commodity);
        }
        System.out.println("华丽的分割线========================");
        System.out.println("排序后:");
        // 根据商品的number属性进行排序
       commodities.stream().sorted(Comparator.comparing(Commodity::getNumber)).collect(Collectors.toList());
        for (Commodity commodity : commodities) {
            System.out.println(commodity);
        }
    }

}

这段程序输出的结果是这样的:

Steam sorted排序 java stream排序无效_JDK8


实际开发中遇到这种情况是不是有点见了鬼的感觉?接到测试同学的bug通知后,我debug跟了一下,发现我一通操作,原来集合竟然没有任何变化。这个时候我怀疑的是sorted方法的使用姿势不对,结果度娘告诉我sorted方法默认是升序的。

Steam sorted排序 java stream排序无效_Steam sorted排序 java_02


写下解决问题的过程,看看你是不是也是这样的?首先百度,谷歌一通关键词搜索,比如:‘Stream流 JDK8 失效’,‘Stream sorted 排序后没变化’。搜索结果还是上面那个表情,没找到答案。实际上这个问题的原因在于:我对集合做了处理却没有去做一个接收的操作。先看一下正确的代码及结果:

Steam sorted排序 java stream排序无效_JDK8_03

Steam sorted排序 java stream排序无效_sorted_04


结论:

使用JDK8新特性Stream流中的任意方法,如filter,map,sorted等方法,都需要接收处理后的集合。这样才可以达到预期的效果!

具体原因如下:(有时间的可以看看!)

首先要知道Stream是JDK8新出的API,是用来简化集合操作的,Stream的核心是集合转化成流,通过流式操作简化之前循环操作集合的过程,它的核心方法的返回值依旧还是一个Steam流,具体可以看下图左侧。

Steam sorted排序 java stream排序无效_JDK8_05


对Stream流不熟悉的同学可能还是不能理解,这边用生活中的事物做个比喻:

Steam sorted排序 java stream排序无效_sorted_06


大家可以把我们的集合当成图片中的水,几个小竹筒实际上对应的就是我们每一步操作过后得到的Stream。也就是说我们的集合就像水流一样在一个个管道中流动。水流经过层层过滤(假设水每经过一个小竹筒都会执行一个操作,比如过滤(filter),筛选(map)等),最终得到我们想要的水。

最终简单说下结果,实际上将集合转换成Stream流(调用stream方法),都是重新new了一个新的Stream,它不是对原来的集合进行操作,具体可以简单看下源码:

Steam sorted排序 java stream排序无效_Steam sorted排序 java_07

初学者看到new即可,new代表新建一个对象,而我们的Stream是一个接口,实际new的是它的实现类。这就是为什么使用Stream一定要接收返回值的原因。这里与BigDecimal有异曲同工之妙,BigDecimal操作数据也是重新new一个新的BigDecimal对象,这里可以一起学习,链接如下:
使用BigDecimal运算结果老是为0?老是没作用?来看看BigDecimal运算的正确姿势吧!