【JAVA】jdk8 Stream 排序精通

news2024/11/26 5:32:18

背景

jdk8的stream流能方便的排序,但是每次都要查资料,非常不方便,不确定,所以这次直接弄懂,不再迷茫。

转载请注明来源,创作不易,请多多支持。

基础排序

stream流 大家应该都比较熟悉了,毕竟jdk8出来多久了,言简意赅的讲解下

stream 流提供的排序的方法其实就两个 :
一个是无参的 Stream<T> sorted();
一个是有参的 Stream<T> sorted(Comparator<? super T> comparator);

基础写法-无参

无参的排序很简单,按照默认排序,测试代码如下

    @Data
    @Builder
    public static class User {
        private String username;
        private Integer age;
    }

    @Test
    public void StreamSort() {
        List<String> list1 = Lists.newArrayList("1", "2", "01", "02", "10", "11", "a");
        List<Integer> list2 = Lists.newArrayList(1, 2, 0, 3, 7);
        List<Boolean> list3 = Lists.newArrayList(true, false, true, false, false);
        List<User> list4 = Lists.newArrayList(User.builder().age(1).build()
                , User.builder().age(2).build()
                , User.builder().age(3).build());
        list1.stream().sorted().forEach(
                p -> System.out.print(p + " ")
        );
    }

结论: 其实只要知道基础类型默认是怎么排序的就好了,对象类型本质还是指定到基础类型去,记住一个词 点名(从小到大)

1、字符串排序结果是 01 02 1 10 11 2 a,字符串比较很简单,就是字符依次比较,从小到大,第一位相同比第二位,依次排序。

2、数值类型排序结果 0 1 2 3 7,数值类型的都是一样的规律,从小到大 和 报数一样

3、布尔类型排序结果 false false false true true,可以类比 0是false 1是true 约定俗成 0为false 1为true, 依然是上升趋势

基础写法-有参

Comparator 是一个专门排序用的接口,只有一个核心方法 int compare(T o1, T o2);

严格的写法

一个匿名内部类实现排序的逻辑

        list2.stream().sorted(
                new Comparator<Integer>() {
                    @Override
                    public int compare(Integer p1, Integer p2) {
                        return p1 - p2;
                    }
                }
        ).forEach(p -> System.out.print(p + " "));

jdk8可以用lambda表达式简写,非数值类型的需要自定义规则

                (p1, p2) -> {
                    return p1 - p2;
                }
                
或者 进一步简写    (p1, p2) ->  p1 - p2

常用便捷写法

大部分其实都是数值比较,除了非数值类型的需要自定义规则,

比如要实现默认的字符串的比较,可以自定义以下逻辑

        list1.stream().sorted((p1, p2) -> {
                    char[] chars1 = p1.toCharArray();
                    char[] chars2 = p2.toCharArray();
                    //取短数组长度
                    for (int i = 0; i < Math.min(chars1.length, chars2.length); i++) {
                        if (chars1[i] != chars2[i]) {
                            return chars1[i] - chars2[i];
                        }
                    }
                    return 0;
                }
        ).forEach(p -> System.out.print(p + " "));

但是对于完全的数值比较,其实就按照默认的比较即可,给Stream 排序的值即可,特别是对象,只需要指定字段即可

        list4.stream().sorted(Comparator.comparingInt(User::getAge)).forEach(p -> System.out.print(p + " "));

支持的数值方法有 comparingIntcomparingLongcomparingDouble

基础写法-倒序

默认的排序是点名,从小到大,而有时候我们需要从大到小

除了自定义的排序方法,还有两种快捷的方式

1、在已完成的Comparator对象上再调用 reversed()方法,依然返回Comparator对象,不过是翻转后的,从小到大就变成了从大到小

2、对于对象,可以直接使用Comparator.comparing(User::getAge,Comparator.naturalOrder()), 这样的快捷构造来指定排序。

第一个就是排序的字段,第二个表示自然的排序naturalOrder(从小到大) 还是倒序reverseOrder (从大到小)

因为对象比基本类型占用空间大,如果排完序之后再翻转,而同时数组长度比较大,那么就可能有性能问题,所以可以直接指定排序的方向,避免不必要的浪费

这一点可以追溯一下,这里传入的第二个参数,其实就是排序方法的实例
在这里插入图片描述

在这里插入图片描述
NaturalOrderComparator 比较是 c1.compareTo(c2);
而 ReverseComparator 比较是 c2.compareTo(c1);

那么就比较明显了,他不是最终翻转而是比较过程中就已经取反了

因此对象排序,优先使用这样的方式去指定排序,特别是倒序的时候

高级排序

部分高级排序用法,程序设计的非常完善,有效好用

空值处理

Stream流处理不会处理空值,也就是Null,如果原始Stream流里面有空值,那么就直接会报空指针异常

如果可能有空值,一般需要过滤掉空值之后再排序,filter 返回布尔值,只保留返回true的数据

        list4.stream().filter(p -> p.getAge() != null)
                .sorted(Comparator.comparing(User::getAge, Comparator.reverseOrder()))
                .forEach(p -> System.out.print(p + " "));

如果空值还需要处理(比如追加列表最后),一般用单独的数组存放

        List<User> emptyList = list4.stream().filter(p -> p.getAge() == null).collect(Collectors.toList());
        List<User> resList = list4.stream().filter(p -> p.getAge() != null)
                .sorted(Comparator.comparing(User::getAge, Comparator.reverseOrder()))
                .collect(Collectors.toList());
        resList.addAll(emptyList);

多字段排序

可能单个字段排序不够,需要两次排序,甚至多次排序

其实也已经提供了现成的方法,thenComparing,同样返回的还是Comparator对象,那么可以继续追加

比如 我的原始数据是

        List<User> list4 = Lists.newArrayList(User.builder().age(1).score(2).build()
                , User.builder().age(2).score(2).build()
                , User.builder().age(2).score(1).build()
                , User.builder().age(2).score(8).build()
                , User.builder().age(3).score(8).username("qiushi").build()
                , User.builder().age(3).score(5).build());

而排序方法是

.sorted(Comparator.comparing(User::getAge, Comparator.naturalOrder()).thenComparing(User::getScore, Comparator.naturalOrder()))

那么最终结果就是先 age 顺序,score顺序

User(username=null, age=1, score=2)
User(username=null, age=2, score=1)
User(username=null, age=2, score=2)
User(username=null, age=2, score=8)
User(username=null, age=3, score=5)
User(username=qiushi, age=3, score=8)

所以你明白了么? 先写到这里,后续再来补充,欢迎讨论指正,biu~

结论速记

1、默认是点名 从小到大排序,空值需自己处理

2、可以自定义排序方法,使用匿名函数(lambda表达式)快速实现,提供快速 转化数值的方法comparingIntcomparingLongcomparingDouble

3、对象如果需要倒序,尽量指定排序方向,Comparator.comparing(User::getAge,Comparator.naturalOrder()),比最后来翻转reversed()的性能更好

4、支持多字段排序,使用thenComparing 方法依次指定

(日常偷图,侵删)
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/345715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react-01-jsx语法与react实例三大属性与react生命周期

英文官网: https://reactjs.org/ 中文官网:https://react.docschina.org/ 基本知识 1、jsx语法 标签中使用js表达式用{} jsx中样式叫className 内联样式使用style{{key:value}}去写 只有一个根标签 标签必须闭合 标签首字母 (1).若小写字母开头&#xff0c;则将该标签…

网络安全领域中CISP证书八大类都有什么

CISP​注册信息安全专业人员 注册信息安全专业人员&#xff08;Certified Information Security Professional&#xff09;&#xff0c;是经中国信息安全产品测评认证中心实施的国家认证&#xff0c;对信息安全人员执业资质的认可。该证书是面向信息安全企业、信息安全咨询服务…

P1217 [USACO1.5]回文质数 Prime Palindromes

[USACO1.5]回文质数 Prime Palindromes 题目描述 因为 151151151 既是一个质数又是一个回文数&#xff08;从左到右和从右到左是看一样的&#xff09;&#xff0c;所以 151151151 是回文质数。 写一个程序来找出范围 [a,b](5≤a<b≤100,000,000)[a,b] (5 \le a < b \l…

idea使用本地代码远程调试线上运行代码---windows环境

场景&#xff1a; 今天在书上看了一个代码远程调试的方法&#xff0c;自己本地验证了一下感觉十分不错&#xff01;&#xff01; windows环境&#xff1a; 启动测试jar包&#xff1a;platform-multiappcenter-base-app-1.0.0-SNAPSHOT.jar 测试工具&#xff1a;postman,idea 应…

java日志查看工具finder介绍

目录 一、finder介绍 二、单节点部署 1、服务器需要安装Tomcat&#xff0c;以2.82.16.35为例 2、进入Tomcat下目录webapps下&#xff0c;创建FIND目录&#xff0c;进入FIDN目录 3、下载findweb插件&#xff0c;解压缩 4、登录页面&#xff0c;配置 5、添加日志路径 三、…

MongoDB 聚合

MongoDB 聚合 MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值&#xff0c;求和等)&#xff0c;并返回计算后的数据结果。 aggregate() 方法 MongoDB中聚合的方法使用aggregate()。 语法 aggregate() 方法的基本语法格式如下所示&#xff1a; >db.COLLECTION…

【基础】性能测试,从0到实战(手把手教,非常实用)

一、性能基础 什么是性能测试--->本质? 基于协议来模拟用户发送的请求&#xff08;业务模拟&#xff09;&#xff0c;对服务器形成一定负载。关注点&#xff1a;时间性能、空间性能与界面无关 性能测试分类 性能测试&#xff08;狭义&#xff09; 性能测试方法是通过模…

2023.2.13 调整接口中日志的调用方法

如下&#xff0c; 这是目前我们在接口中调用的方法&#xff0c;可以看到目前使用的是call mehtod 调用类方法的写法 调用的是ZHA047_CL_TOOL 中的这个SAVSTRU_DEST_R方法 输入为 dest_r (系统区分标识[returing时使用]&#xff0c;用于识别是从哪个系统来的调用命令) 输出为 d…

如何使用微软bing的chatGPT

bing集合了chatGPT&#xff0c;今天介绍一下&#xff0c;如何申请加入到列表&#xff0c;体验一下。未来几个月&#xff0c;bing应该会放开chatGPT的接入&#xff0c;这样国内也可以用到这个技术了。 想要提前用到bing的chatGPT的&#xff0c;可以先按照我的方法申请一下&…

ElasticSearch简介

文章目录ElasticSearch简介正向索引和倒排索引正向索引倒排索引ElasticSearch和MySQL的区别ElasticSearch简介 什么是ElasticSearch&#xff1f; ElasticSearch 是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量的数据中快速找到需要的内容。 什么是ELK&#xff1…

C/C++排序算法(三)—— 冒泡排序和快速排序

文章目录前言1. 冒泡排序&#x1f351; 基本思想&#x1f351; 图解冒泡&#x1f351; 动图演示&#x1f351; 代码实现&#x1f351; 代码优化&#x1f351; 特性总结2. 快速排序&#x1f351; hoare 版本&#x1f345; 图解过程&#x1f345; 动图演示&#x1f345; 代码实现…

K_A12_005 基于STM32等单片机采集红外寻迹避障模块串口与OLED0.96双显示

K_A12_005 基于STM32等单片机采集红外寻迹避障模块串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明模块工作原理:对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC红外寻迹避障模块1.2、STM32F103C8T6红外寻迹避障模块五、基础知识学习与相关资…

R语言系列教程-----一起来学shiny吧(1)

什么是shiny&#xff1f;Shiny是一个R包&#xff0c;可让您轻松地直接从 R 构建交互式 Web 应用程序&#xff08;应用程序&#xff09;。本系列是个长教程&#xff0c;带你由浅入深学习shiny。 我们先使用系统自带的一个例子来介绍一下shiny&#xff0c;我们先导入shiny包 li…

RK3568开发笔记

一、了解MASKROM模式 出厂的时候&#xff0c;没有任何固件&#xff0c;但CPU有一块EPROM存储区&#xff0c;放有一个BOOTROM小启动程序。 这就是MASKROM模式。 使得首次烧写FLASH成为可能&#xff0c;不需要拆FLASH到烧录器上。 在MASKROM下&#xff0c;烧写UPDATE.IMG文件&…

Java实现碧蓝航线连续作战

目录一.实现功能二.主要思路三.代码实现四.用exe4j生成.exe程序五.最终效果六.代码开源一.实现功能 主线图作战结束到结算页自动点击再次前往 二.主要思路 判断是否进入了结算界面&#xff1a;记录结算界面某个像素点的RGB值&#xff0c;每隔3秒对这个像素点进行比对 移动鼠标…

浅入浅出keepalived+nginx实现高可用双机热备

对应用keepalivednginx技术实现nginx高可用进行简单的分析&#xff0c;下面是通过对keepalived添加校验nginx存活脚本&#xff0c;监控nginx的状态&#xff0c;应用keepalived的主备模式实现nginx的高可用。 假如192.168.100.2和192.168.100.3两台机器安装了nginx&#xff0c;负…

C++深入浅出(九)—— 多态

文章目录1. 多态的概念2. 多态的定义及实现&#x1f351; 多态的构成条件&#x1f351; 虚函数&#x1f351; 虚函数的重写&#x1f351; 虚函数重写的两个例外&#x1f351; C11的override 和 final&#x1f351; 重载、覆盖(重写)、隐藏(重定义)的对比3. 抽象类&#x1f351;…

微信中如何接入chatgpt机器人才比较安全(不会收到警告或者f号)之第二步注入dll文件

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂。 前言 上一篇文章我们提到过,微信中如何接入chatgpt机器人才比较安全(不会收到警告或者f号)之第一步登录微信,需要的大家可以点进去看。 文接上篇,本文主要介绍如果将机器人接入到微信中的方法之一,别的方法后面专…

如何快速了解项目源文件的构成?基于 Node.js 实现项目源代码数据统计工具

当希望了解一个项目的代码规模时&#xff0c;首先可能会想对项目源文件的数量、类型分布、代码行数等做一下数据统计。使用 Linux/git 命令可以满足简单的统计需求&#xff0c;使用流行的 cloc 工具可以实现详细的源代码分析数据。此外也可以使用 Node.js 编码简单的实现个性化…

1.7配置OSPF手动汇总

实验7:配置OSPF手动汇总 实验目的实现OSPF路由汇总的配置阐明OSPF引入的外部路由时进行路由汇总的方法实验拓扑配置OSPF手动汇总实验拓扑如图1-17所示。 图1-17 配置OSPF手动汇总 实验步骤配置IP地址,配置OSPF(和实验6一致,此处略)在…