Java8 - lambda 使用 Comparator.comparing()、reversed()、reverseOrder()、nullsFirst()、thenComparing 排序及区别

实体类

/**
 * [Employee(name=John, age=25, salary=3000.0, mobile=9922001),
 * Employee(name=Ace, age=22, salary=2000.0, mobile=5924001),
 * Employee(name=Keith, age=35, salary=4000.0, mobile=3924401)]
 */
 @Data

class Employee {
    private String name;
    private int age;
    private double salary;
    private long mobile;

    // constructors, getters & setters
    
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Employee{");
        sb.append("name='").append(name).append('\'');
        sb.append(", age=").append(age);
        sb.append(", salary=").append(salary);
        sb.append(", mobile=").append(mobile);
        sb.append('}');
        return sb.toString();
    }
}

使用外部比较器Comparator进行排序

当我们需要对集合的元素进行排序的时候,可以使用java.util.Comparator 创建一个比较器来进行排序。Comparator接口同样也是一个函数式接口,我们可以把使用lambda表达式。如下示例,

package com.common;

import java.util.*;
import java.util.stream.Collectors;

public class ComparatorTest {
    public static void main(String[] args) {
        Employee e1 = new Employee("John", 25, 3000, 9922001);
        Employee e2 = new Employee("Ace", 22, 2000, 5924001);
        Employee e3 = new Employee("Keith", 35, 4000, 3924401);

        List<Employee> employees = new ArrayList<>();
        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        /**
         *     sort 对象接收一个 Comparator 函数式接口,可以传入一个lambda表达式
         */
        employees.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));

        Collections.sort(employees, (o1, o2) -> o1.getName().compareTo(o2.getName()));

        employees.forEach(System.out::println);
    }
}

使用 Comparator.comparing 进行排序

comparing 方法一

查看 Comparator 类内部实现,还有一个 comparing 方法,实现如下,

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

其返回值是 (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); 一个lambda表达式,也就是一个Compator 。所以上面那个例子也可以改造成 如下,

        /**
         * Comparator.comparing 方法的使用
         *
         * comparing 方法接收一个 Function 函数式接口 ,通过一个 lambda 表达式传入
         *
         */
        employees.sort(Comparator.comparing(e -> e.getName()));

        /**
         * 该方法引用 Employee::getName 可以代替 lambda表达式
         */
        employees.sort(Comparator.comparing(Employee::getName));

comparing 方法二
    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        Objects.requireNonNull(keyExtractor);
        Objects.requireNonNull(keyComparator);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                              keyExtractor.apply(c2));
    }

和comparing 方法一不同的是 该方法多了一个参数 keyComparator ,keyComparator 是创建一个自定义的比较器。

Collections.sort(employees, Comparator.comparing(
                Employee::getName, (s1, s2) -> {
                    return s2.compareTo(s1);
                }));

使用 Comparator.reversed 进行排序

返回相反的排序规则,

/**
 *  相反的排序规则
 */
Collections.sort(employees, Comparator.comparing(Employee::getName).reversed());

employees.forEach(System.out::println);

输出,

Employee{name='Keith', age=35, salary=4000.0, mobile=3924401}
Employee{name='John', age=25, salary=3000.0, mobile=9922001}
Employee{name='Ace', age=22, salary=2000.0, mobile=5924001}

使用 Comparator.nullsFirst进行排序

当集合中存在null元素时,可以使用针对null友好的比较器,null元素排在集合的最前面

employees.add(null);  //插入一个null元素
Collections.sort(employees, Comparator.nullsFirst(Comparator.comparing(Employee::getName)));
employees.forEach(System.out::println);


Collections.sort(employees, Comparator.nullsLast(Comparator.comparing(Employee::getName)));
employees.forEach(System.out::println);

使用 Comparator.thenComparing 排序

首先使用 name 排序,紧接着在使用ege 排序,来看下使用效果

Collections.sort(employees, Comparator.comparing(Employee::getAge).thenComparing(Employee::getName));
employees.forEach(System.out::println);

reversed()和Comparator.reverseOrder()排序区别

  • Comparator.comparing(类::属性一).reversed();

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

方式 1:是得到排序结果后再排序;

方式2:是直接进行排序,很多人会混淆导致理解出错, 该方式更好理解

List<Object> list; 
 
//对象集合以类属性一升序排序
list.stream().sorted(Comparator.comparing(::属性一));
 
//对象集合以类属性一降序排序,两种方式写法对比:
list.stream().sorted(Comparator.comparing(::属性一).reversed());//方式1:先以属性一升序,结果再进行降序
list.stream().sorted(Comparator.comparing(::属性一,Comparator.reverseOrder()));//方式2:直接以属性一降序
 
//对象集合以类属性一升序、属性二升序排序
list.stream().sorted(Comparator.comparing(::属性一).thenComparing(::属性二));
 

//对象集合以类属性一降序、属性二升序 注意两种写法
list.stream().sorted(Comparator.comparing(::属性一).reversed().thenComparing(::属性二));//方式1:先以属性一升序,升序结果进行属性一降序,再进行属性二升序
list.stream().sorted(Comparator.comparing(::属性一,Comparator.reverseOrder()).thenComparing(::属性二));//方式2:先以属性一降序,再进行属性二升序
 
//返回 对象集合以类属性一降序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(::属性一).reversed().thenComparing(::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
list.stream().sorted(Comparator.comparing(::属性一,Comparator.reverseOrder()).thenComparing(::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序
 
//返回 对象集合以类属性一升序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(::属性一).reversed().thenComparing(::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
list.stream().sorted(Comparator.comparing(::属性一).thenComparing(::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序

//空/Null数据排序
list.stream().sorted(Comparator.comparing(::属性一).thenComparing(item -> item.属性二, Comparator.nullsLast(Date::compareTo))).collect(Collectors.toList());

//空/Null数据分组
Map<String, List<>> map = list.stream().collect(Collectors.groupingBy(item -> {
  if (item.属性一 == null || item.属性一.equals("")) {
    return "";
  }
  return DateFormat.getDateInstance().format(item.属性一);
}))

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值