Java中的排序(stream多字段排序踩坑)

3,370 阅读4分钟

由于粉丝大多数是小白本篇文章会啰嗦一些,敬请谅解!高手请忽略文章介绍直入代码主题。

一、介绍

  • Java 8 API添加了一个新的抽象层流Stream,它以一种声明的方式处理数据,最后由最终操做获得前面处理的结果。

  • Stream专一于集合对象的操做,将要处理的元素集合看做一种流, 流在管道中传输, 而且能够在管道的节点上进行处理, 好比筛选, 排序,聚合等。

  • Stream在处理大批量数据操做中更加高效。

  • Stream + Lambda 表达式能够极大提升Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

  • stream的三大特性:一、不存储数据;二、不改变源数据;三、延时执行。

  • stream优势:一、简化代码;二、使用并行流能够利用多核特性,提高效率。

  • stream上的全部操做分为两类:中间操做和结束操做,中间操做只是一种标记,只有结束操做才会触发实际计算。

二、什么是流

  • Stream不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的Iterator。原始版本的Iterator,用户只能显式地一个一个遍历元素并对其执行某些操做;高级版本的Stream,用户只要给出须要对其包含的元素执行什么操做,好比,“过滤掉长度大于 10 的字符串”、“获取每一个字符串的首字母”等,Stream会隐式地在内部进行遍历,作出相应的数据转换。Stream就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就比如流水从面前流过,一去不复返。

  • 而和迭代器又不一样的是,Stream能够并行化操做,迭代器只能命令式地、串行化操做。顾名思义,当使用串行方式去遍历时,每一个item读完后再读下一个item。而使用并行去遍历时,数据会被分红多个段,其中每一个段在不一样的线程中处理,而后将结果一块儿输出。Stream的并行操做依赖于Java7中引入的Fork/Join框架(JSR166y)来拆分任务和加速处理过程。

  • Stream 的另一大特色是,数据源自己能够是无限的。

  • 工做中,常常会须要对集合内的元素进行排序。利用Java8能够很方便的对List内的元素进行排序操做;而在不少状况下sql很差

  • 解决的多表查询,临时表分组,排序,尽可能用java8新特性stream进行处理。

三、如何使用

List 倒序排列
List<Double> salesData = new ArrayList<>();

Collections.reverse(salesData);
java8 stream多字段排序
List<类> rankList = new ArrayList<>(); //表明某个集合
 
//返回 对象集合以类属性一升序排序
 
rankList.stream().sorted(Comparator.comparing(类::属性一));
 
//返回 对象集合以类属性一降序排序 注意两种写法
 
rankList.stream().sorted(Comparator.comparing(类::属性一).reversed()); //先以属性一升序,而后对结果集进行属性一降序
 
rankList.stream().sorted(Comparator.comparing(类::属性一, Comparator.reverseOrder())); //以属性一降序
 
//返回 对象集合以类属性一升序 属性二升序
 
rankList.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));
 
//返回 对象集合以类属性一降序 属性二升序 注意两种写法
 
rankList.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序
 
rankList.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序
 
//返回 对象集合以类属性一降序 属性二降序 注意两种写法
 
rankList.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
 
rankList.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序
 
//返回 对象集合以类属性一升序 属性二降序 注意两种写法
 
rankList.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
 
rankList.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序
  • 注意两种写法
一、 Comparator.comparing(类::属性一).reversed();

二、 Comparator.comparing(类::属性一,Comparator.reverseOrder());

两种排序是彻底不同的,必定要区分开来:方式1是获得排序结果后再排序,方式2是直接进行排序!!!方式2更好理解。 关于java8 的stream排序用法到此介绍完毕。接下来是采坑的地方

四、踩坑

  • 关于java8 的stream排序用法上面有说,介绍在多字段排序时遇到过的一个坑。
  • 需求:须要根据id去分组,而后取出每组中行号最大的一个对象值。 想到能够利用stream的多字段排序,先按id去排,再看行号去排,demo代码以下:
/**
 * Author  : PH
 * Date    : 2022/4/6
 * ApiNote : 实体类
 */
public class Tt {
    private int id;

    private int line;

    public Tt(int id, int line) {
        this.id = id;
        this.line = line;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getLine() {
        return line;
    }

    public void setLine(int line) {
        this.line = line;
    }

    @Override
    public String toString() {
        return "Tt{" +
                "id=" + id +
                ", line=" + line +
                '}';
    }
}

对象代码如上,只提供id和行号字段,作演示用: 测试代码以下:

public static void main(String[] args) {
        List<Tt> list = new ArrayList<>();

        list.add(new Tt(1,2));
        list.add(new Tt(2,2));
        list.add(new Tt(5,2));
        list.add(new Tt(5,1));
        list.add(new Tt(4,2));
        list.add(new Tt(7,2));
        list.add(new Tt(3,2));

        List<Tt> sortedList = list.stream() .sorted(Comparator.comparing(Tt::getId)).sorted(Comparator.comparing(Tt::getLine))
                .collect(Collectors.toList());

        System.err.println(sortedList);
    }

根据理论,应该是先根据id去排好序,再根据行号去排号序,效果应该是,按id顺序打印的。结果以下:

image.png 发现其实并非想像的效果,结果是按后者顺序打印的。 由此推断出,当须要用到stram多条件排序的时候,须要最后排序的字段须要放在前面排,改后代码以下:

List<Tt> sortedList = list.stream() .sorted(Comparator.comparing(Tt::getLine)).sorted(Comparator.comparing(Tt::getId))
         .collect(Collectors.toList());

效果以下: !

image.png 达到预期,问题解决!

相关文章

java8 stream多字段排序

嵌套List排序,java8 Stream流排序

java8的Stream的排序

java8的stream用于排序

java8新特性stream流

Java8新特性---Stream(流)

Java8新特性——stream流

JAVA8新特性之Stream流

Java8新特性--流(Stream)

java8 stream代替for循环 sort多字段排序 group by多级排序

java8 stream排序空字段排在前面或后面

Java8 stream根据字段分组并排序

JAVA8 Stream 映射 排序

List使用stream单字段排序

Java8中的Stream()与ParallelStream()的区别;

Java集合Stream类filter的使用