Stream流对多个字段进行排序

在Java8中,你可以使用Stream接口的sorted()方法来对集合中的元素进行排序。这个方法接受一个Comparator对象作为参数,用于定义排序规则。如果你需要根据多个字段进行排序,你可以链式地调用thenComparing()或thenComparingInt()、thenComparingLong()、thenComparingDouble()等方法。

准备数据:

package com.morris.java8.sort;

import java.util.ArrayList;
import java.util.List;

public class Person {

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static List<Person> noNullPersonList() {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("Morris", 18));
        personList.add(new Person("Bob", 16));
        personList.add(new Person("Tom", 20));
        personList.add(new Person("Jack", 18));
        personList.add(new Person("Marry", 21));
        personList.add(new Person("Jim", 17));
        return personList;
    }

    public static List<Person> nullablePersonList() {
        List<Person> personList = noNullPersonList();
        personList.add(new Person("Herry", null));
        personList.add(new Person(null, 19));
        return personList;
    }
}

正序
naturalOrder()表示自然排序(一般是升序),数字的自然顺序是数字顺序,字符串按字母顺序排序,日期按时间顺序排序

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 按年龄正序排列
 */
public class AgeAscOrderDemo {
    public static void main(String[] args) {
        // Comparator.comparingInt
        // order by age asc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge)).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // Comparator.comparing + Comparator.naturalOrder
        // order by age asc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.naturalOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);
    }
}

倒序
reverseOrder()表示降序。

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 按年龄倒序排列
 */
public class AgeDescOrderDemo {
    public static void main(String[] args) {
        // Comparator.comparingInt + Comparator.reversed
        // order by age desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).reversed()).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // Comparator.comparing + Comparator.reverseOrder
        // order by age desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);
    }
}

对null字段排序的处理
没有处理属性的null值,排序时可能会空指针:

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 对字段中包含null的数据排序抛出异常
 */
public class NullFieldOrderExceptionDemo {
    public static void main(String[] args) {
        Optional.of(Person.nullablePersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge)).collect(Collectors.toList()))
                .ifPresent(System.out::println);
    }
}

上面的代码会抛出如下异常:
在这里插入图片描述
如果排序的字段中包含null,就要对null进行特殊处理:

nullsLast()表示如果属性为null,就放到最后面。
nullsFirst()表示如果属性为null,就放到最前面。

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 对字段中包含null的数据进行排序
 */
public class NullFieldOrderDemo {
    public static void main(String[] args) {
        // Comparator.nullsFirst
        Optional.of(Person.nullablePersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // Comparator.nullsLast
        Optional.of(Person.nullablePersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.nullsLast(Comparator.naturalOrder()))).collect(Collectors.toList()))
                .ifPresent(System.out::println);
    }
}

多字段排序
有时我们还需要对多个字段进行排序。

多个字段排序,先对第一个排序字段排序,当第一个排序字段相同时,会使用第二个排序字段进行排序。

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 对多个字段进行排序
 */
public class MultiFieldOrderDemo {
    public static void main(String[] args) {
        // 对年龄升序,对名字升序
        // order by age asc,name asc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName)).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // 对年龄升序,对名字降序
        // order by age asc,name desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName, Comparator.reverseOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // 对年龄降序,对名字升序
        // order by age desc,name asc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder()).thenComparing(Person::getName)).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // 对年龄降序,对名字降序
        // order by age desc,name desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder()).thenComparing(Person::getName, Comparator.reverseOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);

    }
}

运行结果如下:

[Person{name='Bob', age=16}, Person{name='Jim', age=17}, Person{name='Jack', age=18}, Person{name='Morris', age=18}, Person{name='Tom', age=20}, Person{name='Marry', age=21}]
[Person{name='Bob', age=16}, Person{name='Jim', age=17}, Person{name='Morris', age=18}, Person{name='Jack', age=18}, Person{name='Tom', age=20}, Person{name='Marry', age=21}]
[Person{name='Marry', age=21}, Person{name='Tom', age=20}, Person{name='Jack', age=18}, Person{name='Morris', age=18}, Person{name='Jim', age=17}, Person{name='Bob', age=16}]
[Person{name='Marry', age=21}, Person{name='Tom', age=20}, Person{name='Morris', age=18}, Person{name='Jack', age=18}, Person{name='Jim', age=17}, Person{name='Bob', age=16}]

reversed()和Comparator.reverseOrder()
在前面的例子中,我们看到reversed()和Comparator.reverseOrder()都能进行类似倒序的排序,那么这两个方法有什么区别呢?

两个方法的声明如下:
Comparator.comparing(对象的类名::属性的方法名).reversed();
Comparator.comparing(对象的类名::属性的方法名,Comparator.reverseOrder());

明:

reversed()是得到排序结果后再反转,
Comparator.reverseOrder()是对属性按照降序进行排序,
reversed()在多字段排序时,很容易混乱,不建议使用。
Comparator.reverseOrder()更好理解,也更好用些。
可以通过下面的例子看到两者的区别:

package com.morris.java8.sort;

import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * reversed()与Comparator.reverseOrder()的区别
 */
public class ReverseOrderDemo {
    public static void main(String[] args) {
        // 对年龄升序,对名字降序
        // order by age asc,name desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName, Comparator.reverseOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // 对年龄升序,对名字升序
        // order by age asc,name asc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName)).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // 对上面例子的结果进行反转
        // 先order by age asc,name asc,然后进行反转,实际上就是order by age desc,name desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName).reversed()).collect(Collectors.toList()))
                .ifPresent(System.out::println);

        // order by age desc,name desc
        Optional.of(Person.noNullPersonList().stream()
                .sorted(Comparator.comparing(Person::getAge, Comparator.reverseOrder()).thenComparing(Person::getName, Comparator.reverseOrder())).collect(Collectors.toList()))
                .ifPresent(System.out::println);

    }
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

princeAladdin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值