当前位置: 代码网 > it编程>编程语言>Java > java stream使用指南之sorted使用及进阶方式

java stream使用指南之sorted使用及进阶方式

2024年05月28日 Java 我要评论
引入用了一段时间的jdk8的新特性,lambda表达式、方法引用、stream流,用起来是真的顺手啊,最近碰到了一个排序的问题,引发了一些思考,然后就写了这篇博客,归纳总结sorted的用法,在做笔记

引入

用了一段时间的jdk8的新特性,lambda表达式、方法引用、stream流,用起来是真的顺手啊,最近碰到了一个排序的问题,引发了一些思考,然后就写了这篇博客,归纳总结sorted的用法,在做笔记的同时也让自己有更深的理解。

数据准备

1. 依赖

我喜欢用google的集合工具类,让我构造测试数据更简便。

然后也用lombok,依赖:

        <!--google集合工具类-->
        <dependency>
            <groupid>com.google.guava</groupid>
            <artifactid>guava</artifactid>
            <version>30.0-jre</version>
        </dependency>

			<!--lombok,需要插件配合使用-->
        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
            <version>1.18.12</version>
        </dependency>

2. 相关类

user类

/*
*链式调用,我也有写相关博客,不过不是介绍基础用法的,是这个链式调用一个不太完美的地方,
*感兴趣的可以去看一看:https://blog.csdn.net/ql_7256/article/details/120274432 
*/
@data
@accessors(chain = true) 
public class user  {

    private string username;
    private string password;
    private integer age;
    private integer height;

    private address address;

    private map others;

}

address类,注意:这个类在后续的测试中要改动

@data
@accessors(chain = true)
public class address {

    private string province;
    private string city;
    private string county;
    
}

数据准备,

    private list<user> users = new arraylist<user>() {{
        add(new user().setusername("张三").setpassword("123456").setage(20).setheight(170)
                .setaddress(new address().setprovince("四川省").setcity("成都市").setcounty("武侯区"))
                .setothers(immutablemap.builder().put("sorted","aaa").put("bbb","bbb").put("ccc","ccc").build()));

        add(new user().setusername("李四").setpassword("123456").setage(16).setheight(175)
                .setaddress(new address().setprovince("四川省").setcity("成都市").setcounty("锦江区"))
                .setothers(immutablemap.builder().put("sorted","ddd").put("eee","eee").put("fff","fff").build()));

        add(new user().setusername("王五").setpassword("123456").setage(20).setheight(180)
                .setaddress(new address().setprovince("四川省").setcity("成都市").setcounty("青羊区"))
                .setothers(immutablemap.builder().put("sorted","ggg").put("hhh","hhh").put("iii","iii").build()));

        add(new user().setusername("赵六").setpassword("123456").setage(17).setheight(168)
                .setaddress(new address().setprovince("四川省").setcity("成都市").setcounty("高新区"))
                .setothers(immutablemap.builder().put("sorted","jjj").put("kkk","kkk").put("lll","lll").build()));
    }};


    private list<string> strings = new arraylist<string>() {{
        add("222");add("666");add("444");add("111");add("333");add("555");
    }};

    private list<integer> integers = new arraylist<integer>() {{
        add(222);add(555);add(666);;add(333);add(444);add(111);
    }};

    private list others = new arraylist() {{
        add(444);add(555);add(666);add(111);add(222);add(333);
    }};

初体验

stream流、方法引用、lambda那些前置知识咱们就不说了哈,直接上手,先体直观的验一下排序

        list<string> sortedstrings = strings.stream().sorted().collect(collectors.tolist());
        
        // [111, 222, 333, 444, 555, 666]
        system.out.println(sortedstrings);

        
        
        list<user> sortedusers = users.stream().sorted(comparator.comparing(e -> e.getage())).collect(collectors.tolist());
        // 等效写法如下
        // list<user> sortedusers = users.stream().sorted(comparator.comparing(user::getage)).collect(collectors.tolist());
        
        // [user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii})]
        system.out.println(sortedusers);

很简单,也没啥难理解的,就是排序

基础用法

排序的初体验之后,我们来看看几种正式场景下的使用

1. 降序几种方式

在上面的体验排序中,排序的结果默认都是升序的,那如果我要降序呢?那怎么办?有三种方式,或者三种写法

1. 使用reversed

根据user中的age降序

        list<user> collect = users.stream().sorted(comparator.comparing(user::getage).reversed()).collect(collectors.tolist());
        // [user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff})]
        system.out.println(collect);

根据user中age先排序,默认情况下是升序,然后再逆序一下,就变成了降序。但是这样有点不好,因为是先排序然后在逆序的,要两步操作。

2.使用comparator.reverseorder

根据user中的age降序

        list<user> collect1 = users.stream().sorted(comparator.comparing(user::getage, comparator.reverseorder())).collect(collectors.tolist());
        // [user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff})]
        system.out.println(collect1);

这种方式原理和和方法1差不多,只是写法不一样

3. 在sorted中使用compareto

方式1和方式2都是利用sorted默认序,然后再逆序来实现排序的,这样会有两个步骤,先升序,然后再逆序。难道就没有直接按照降序来排序的方法?肯定是有的。既然是排序,肯定是可以指定规则的

  • 按照年龄降序
        list<user> collect2 = users.stream().sorted((x, y) -> y.getage().compareto(x.getage())).collect(collectors.tolist());
        // [user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff})]
        system.out.println(collect2);

这种方式是通过integer中的compareto方法来实现降序的,当然也可以自己实现,只不过age是integer类型,既然integer中已经实现两个integer比较的方法,就可以偷个懒

4. 在sorted自定义规则

        list<user> collect3 = users.stream().sorted((x, y) -> y.getage() - x.getage()).collect(collectors.tolist());
        // [user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff})]
        system.out.println(collect3);

比较实际的最终结果就是返回一个数字,大于0、小于0、等于0,分别就代表大于、小于、等于,所以在sorted方法中返回一个做减法的数字即可。

2. 多级排序

比如我现在的需求是先按照年龄降序,年龄相同的再按照名字降序

list<user> collect = users.stream().sorted(comparator.comparing(user::getage, comparator.reverseorder()).thencomparing(user::getheight, comparator.reverseorder())).collect(collectors.tolist());
 // [user(username=王五, password=123456, age=20, height=180, address=address(province=四川省, city=成都市, county=青羊区), others={sorted=ggg, hhh=hhh, iii=iii}), user(username=张三, password=123456, age=20, height=170, address=address(province=四川省, city=成都市, county=武侯区), others={sorted=aaa, bbb=bbb, ccc=ccc}), user(username=赵六, password=123456, age=17, height=168, address=address(province=四川省, city=成都市, county=高新区), others={sorted=jjj, kkk=kkk, lll=lll}), user(username=李四, password=123456, age=16, height=175, address=address(province=四川省, city=成都市, county=锦江区), others={sorted=ddd, eee=eee, fff=fff})]
system.out.println(collect);

thencomparing顾名思义,再比较

进阶

放在以前,我肯定会从stream 排序的api说起,看看有哪些方法,再看怎么调用,但是这流式太过抽象,所以我先讲了怎么用,再回头来看看有哪些api,本质是什么

1. 本质

在java.util.stream.stream中,sorted方法有两个重载形式

sorted

一个是无参,一个是需要一个参数java.util.comparator。

1. stream sorted();

其实这两个方法我们都用过,在初体验中,第一个就是无参的,这样会根据默认规则排序,至于默认规则是什么,就是排序对象实现的java.lang.comparable接口中的compareto方法,不然你试试跑一下这个

list<user> collect = users.stream().sorted().collect(collectors.tolist());

直接报错,报错的原因就是,你要排序一堆user,但是sorted这个无参的方法不知道排序的规则是什么。所以,在使用这个无参的方法时,被排序的元素必须得实现java.lang.comparable接口,来指定排序规则。

2. stream sorted(comparator<? super t> comparator);

除了初体验中的第一个排序,其他的全都是使用的这个方法,很神奇是吧?我好像传的参数不止这样。

但事实上就是这样子,只传了这个一个参数,无非有两种传参形式:一种是确确实实的传了一个java.util.comparator进去,另外一种是自己实现了java.util.comparator中的抽象方法compare,这个方法用来进行元素间的比较。因为java.util.comparator是一个函数式接口,接口中只有compare这一个抽象方法,所以可以结合lambda表达式使用。

我们使用的.sorted(comparator.comparing(……))其实就是直接传了一个comparator进去,因为comparator.comparing这个方法:java.util.comparator#comparing(java.util.function.function<? super t,? extends u>, java.util.comparator<? super u>) 返回的就是一个comparator。

而类似这种使用:sorted((x, y) -> y.getage().compareto(x.getage()))或者sorted((x, y) -> y.getage() - x.getage()),其实就是我们自己在实现java.util.comparator中的抽象方法compare,这其实就是匿名内部类---->简化---->lambda表达式的这么一个过程,其实还可以简化成 方法引用。

2. 拓展及思考

list<user> sortedusers = users.stream().sorted(comparator.comparing(x -> x.getothers().get("aaa").tostring())).collect(collectors.tolist());
list<user> sortedusers2 = users.stream().sorted(comparator.comparing(x -> x.getothers().get("aaa").tostring()).reversed()).collect(collectors.tolist());

为什么第二个排序会有问题?

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com