文章目录

  • 一、数组排序
  • 1、基本数据类型
  • 2、包装类排序
  • 二、Java 自定义排序
  • 1、实现 Comparable 接口并重写 compareTo() 方法
  • 2、实现 Comparator 接口,重写 compare() 方法。
  • 三、java 中同类对象之间的 compareTo() 和 compare() 方法对比分析
  • compareTo() 方法
  • compare()方法
  • Interface Comparable < T >
  • Interface Comparator<T>
  • method
  • 四、Java Comparator
  • 1. 排序(也可以让类实现 Comparable 接口,实现后该类的实例具有排序能力)。
  • 2.分组
  • 五、Java Comparator.comparing | 提取对象属性,按照指定规则排序
  • 1、Comparator.comparing
  • 2、Comparator.comparingInt
  • 3、Comparator.comparingLong
  • 4、Comparator.comparingDouble


一、数组排序

public class Arrays {
	public static void sort(int[] a)
	public static <T> void sort(T[] a, Comparator<? super T> c) 
}

public interface Comparable<T> {  
    public int compareTo(T o);
}

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj); 
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
    
    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }

    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }

 
    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
        return thenComparing(comparingInt(keyExtractor));
    }

 
    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
        return thenComparing(comparingLong(keyExtractor));
    }

  
    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        return thenComparing(comparingDouble(keyExtractor));
    }

  
    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }

  
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }

  
    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }

 
    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(false, comparator);
    }

   
    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));
    }

 
    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));
    }
  
    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
    }


    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {    
    ...   
    }

  
    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {    
    ...      
    }
}

1、基本数据类型

以 int[] 为例:

// 对指定的 int 型数组按数字升序进行排序。
public static void sort(int[] a)
// 对指定 int 型数组的指定范围按数字升序进行排序。排序的范围 [fromIndex, toIndex)。
public static void sort(int[] a, int fromIndex, int toIndex)

升序排序:Arrays.sort 方法

import java.util.Arrays;
int[] arr = {10, 3, 6, 1, 4, 5, 9};
Arrays.sort(arr);

降序排序:升序排序,逆序访问赋值。

Arrays.sort(arr);
int[] descArray = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
        descArray[i] = array[arr.length - i - 1];
}

2、包装类排序

jdk 类库中的包装类已经重写了 Compare 方法,即有默认排序规则,例如对于 Integer 类型会比较其包装的值类型大小,对于 String 类型会以长度最小字符串为基准,逐一比较相同位置字符的 ASCII 码大小,如果都相同则比较字符串的长度。

public static <T> void sort(T[] a, Comparator<? super T> c)

可以自定义比较器,实现函数式接口。

// Integer[],默认升序排序
Integer[] a = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5};
Arrays.sort(a)

// 降序排序 
Arrays.sort(a, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
});
// lambda 写法
Arrays.sort(a, (o1, o2) -> o2 - o1);

二、Java 自定义排序

Arrays.sort() 方法可以对原始类型(基本数据类型)和对象类型进行排序;而 Collections.sort() 只能对集合进行排序,也是通过 Arrays.sort() 方法实现的。

java.util.Collections 中的静态方法的 Collections.sort() 主要是针对集合框架中的动态数组,链表,树,哈希表等( ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap )进行排序。

JDK 中大部分的类都实现了 Comparable 接口,拥有 compareTo 方法。如 Integer,String 等。

1、实现 Comparable 接口并重写 compareTo() 方法

int java.lang.Integer.compare(int x, int y)

Compares two int values numerically. The value returned is identical to what would be returned by:
Integer.valueOf(x).compareTo(Integer.valueOf(y))

Parameters:
x the first int to compare
y the second int to compare

Returns:
the value 0 if x == y; a value less than 0 if x < y; and a value greater than 0 if x > y

Since:
The method compare(int, int) in the type Integer is not applicable for the arguments

2、实现 Comparator 接口,重写 compare() 方法。

将实现好的接口作为参数传入 Arrays.sort() 或 Collections.sort()。

import java.util.Arrays;
import java.util.Comparator;
import java.util.Collections;

String[] str = {"abc","aa","abcd","abcde","bb","abcedf"};
// 自定义排序 按长度排序
Arrays.sort(str, new CompLen());
// Arrays.sort(str, (a, b) -> a.length() - b.length());
System.out.println(Arrays.toString(str));
// 降序 Collections.reverseOrder()
Integer[] a = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5};
Arrays.sort(a, Collections.reverseOrder());

class CompLen implements Comparator<String>{
    @Override
    public int compare(String o1, String o2) {
		return o1.length() - o2.length(); // 也可以实现降序排列 o2.length() - o1.length();
	}
}

compareTo(Object o) 方法是 java.lang.Comparable 接口中的方法,当需要对某个类的对象进行排序时,该类需要实现 Comparable 接口的,必须重写 public int compareTo(T o) 方法。

它强行将实现它的每一个类的对象进行整体排序-----称为该类的自然排序,实现此接口的对象列表和数组可以用 Collections.sort() 和Arrays.sort() 进行自动排序;也就是说,只要实现了这个接口的对象(数组)就相当于有了排序的能力,所以叫做 comparable —可排序的,是一种 内部排序的方式,通过实现它唯一的方法 compareTo()

compare(Object o1,Object o2) 方法是 java.util.Comparator 接口的方法,它实际上用的是待比较对象的 compareTo(Object o) 方法。
对于它,则是针对一些本身没有比较能力的对象(数组)为它们实现比较的功能,所以它叫做 比较器,是一个外部的东西,通过它定义比较的方式,再传到 Collection.sort() 和 Arrays.sort() 中对目标排序,而且通过自身的方法 compare() 定义比较的内容和结果的升降序。

三、java 中同类对象之间的 compareTo() 和 compare() 方法对比分析

java 中同类对象之间的比较又分为两种,基本类型之间的比较和引用类型之间的比较

“==” 是一个比较运算符,基本数据类型比较的是值,引用数据类型比较的是地址值。 (比较地址值即是指是否为同一个对象的引用)
equals() 是一个方法,只能比较引用数据类型。 重写前比较的是地址值,重写后比一般是比较对象的值。

以上两种所述的方式都是只能比较对象与对象相不相等,往往需要的是它们之间的大小比较,当然对于基本类型值大小之间的比较,常用的是 “>”,但关于对象与对象之间的大小比较,主要有类实现 Comparable 接口(重写 compareTo() 方法),或提供 Comparator 接口(重写 compare() 方法)。

compareTo() 方法

重写 compareTo() 方法是实现 Comparable 接口的使用(自然排序)规则:如果当前对象 this 大于形参对象 obj,则返回正整数,如果当前对象 this 小于形参对象 obj, 则返回负整数。如果当前对象 this 等于形参对象 obj, 则返回零。

public class Test {
	public static void main(String[] args) {	
		Student stu1 = new Student("hubert",20);		
		Student stu2 = new Student("jake",18);		
		System.out.println(stu1.compareTo(stu2));//结果为 1	
	}
}

class Student implements Comparable{
	private String name;
	private int age;
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public int compareTo(Student o) {
		return this.age
	}
}

compare()方法

重写 compare() 方法是提供 Comparator 接口的使用 (定制排序)。重写 compare(Object o1, Object o2) 方法,比较 o1 和 o2 的大小,如果方法返回正整数,则表示 o1 大于 o2, 如果返回 0,表示二者相等,如果返回负整数,表示 o1 小于 o2.

引入原因:当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码,或者实现了 java.lang.Comparable 接口的排序规则不适合当前的操作可以考虑使用 Comparator 的对象来实现排序。

import java.util.Comparator;

public class Test {
	public static void main(String[] args) {	
		Student stu1 = new Student("hubert",20);		
		Student stu2 = new Student("jake",18);		
		int compare = new Comparator() {	
			@Override			
			public int compare(Student o1, Student o2) {			
				return o1.getAge() < o2.getAge() ? -1 : o1.getAge() == o2.getAge() ? 0 : 1;
			}
		}.compare(stu1, stu2);
		System.out.println(compare);
	}
}

class Student{
	private String name;
	private int age;
	public Student(String name, int age) {	
		this.name = name;		
		this.age = age;
	}	
	public int getAge() {	
		return age;	
	}
}

Comparator 接口有两个抽象方法,一个是 compare,另一个是 equals 方法,而写这个匿名内部类时,可以不重写 equals 方法,但所有的类都继承 Object, 所以可以不实现 equals 方法。

Module java.base Package java.lang

Interface Comparable < T >

public interface Comparable < T > This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class’s natural ordering, and the class’s compareTo method is referred to as its natural comparison method. Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

int compareTo(T o)
Compares this object with the specified object for order.

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

Parameters: o - the object to be compared.
Returns: a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Throws:
NullPointerException - if the specified object is null
ClassCastException - if the specified object’s type prevents it from being compared to this object.

两个字符串比较返回 ASCII 的差。

String a = "a";
String b = "c";        
System.out.println(a.compareTo(b));

字符串和子串比较返回长度差。

String a = "a1";
String b = "a12345678";        
System.out.println(a.compareTo(b));

返回为正数表示 a > b, 返回为负数表示 a < b, 返回为 0 表示 a == b;

Error:Cannot invoke compareTo(int) on the primitive type int
只能比较引用数据类型,原生类型比较需要包装类。

模块 java.base 包 java.util

Interface Comparator

Type Parameters: T - the type of objects that may be compared by this comparator

public interface Comparator
A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order. Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don’t have a natural ordering.

method

int compare(T o1, T o2) Compares its two arguments for order.
default Comparator reversed() Returns a comparator that imposes the reverse ordering of this comparator.

static <T,U extends Comparable<? super U>> Comparator
comparing(Function<? super T,? extends U> keyExtractor)
Accepts a function that extracts a Comparable sort key from a type T, and returns a Comparator that compares by that sort key.
static <T,U> Comparator comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
Accepts a function that extracts a sort key from a type T, and returns a Comparator that compares by that sort key using the specified Comparator.
static Comparator comparingDouble(ToDoubleFunction<? super T> keyExtractor)
Accepts a function that extracts a double sort key from a type T, and returns a Comparator that compares by that sort key.
static Comparator comparingInt(ToIntFunction<? super T> keyExtractor)
Accepts a function that extracts an int sort key from a type T, and returns a Comparator that compares by that sort key.
static Comparator comparingLong(ToLongFunction<? super T> keyExtractor)
Accepts a function that extracts a long sort key from a type T, and returns a Comparator that compares by that sort key.
boolean equals(Object obj) Indicates whether some other object is “equal to” this comparator.
static <T extends Comparable<? super T>> Comparator naturalOrder()
Returns a comparator that compares Comparable objects in natural order.
static Comparator nullsFirst(Comparator<? super T> comparator)
Returns a null-friendly comparator that considers null to be less than non-null.
static Comparator nullsLast(Comparator<? super T> comparator)
Returns a null-friendly comparator that considers null to be greater than non-null.

static <T extends Comparable<? super T>> Comparator reverseOrder()
Returns a comparator that imposes the reverse of the natural ordering.
default Comparator thenComparing(Comparator<? super T> other)
Returns a lexicographic-order comparator with another comparator.
default <U extends Comparable<? super U>> Comparator
thenComparing(Function<? super T,? extends U> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a Comparable sort key.
default Comparator thenComparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator.
default Comparator thenComparingDouble(ToDoubleFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a double sort key.
default Comparator thenComparingInt(ToIntFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts an int sort key.
default Comparator thenComparingLong(ToLongFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a long sort key.

四、Java Comparator

java.util

Arrays.sort(T[],Comparator<? super T> c);
Collections.sort(List<T> list,Comparator<? super T> c);

1. 排序(也可以让类实现 Comparable 接口,实现后该类的实例具有排序能力)。

在 List 或数组中的对象如果没有实现 Comparable 接口时,那么就需要调用者为需要排序的数组或 List 设置一个Compartor,Compartor 的 compare 方法用来告诉代码应该怎么去比较两个实例,然后根据比较结果进行排序

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortTest {
    class Dog {
        public int age;
        public String name;

        public Dog(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }

        @Override
        public String toString() {
            return "Dog [age=" + age + ", name=" + name + "]";
        }
    }

    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        list.add(new SortTest().new Dog(5, "DogA"));
        list.add(new SortTest().new Dog(6, "DogB"));
        list.add(new SortTest().new Dog(7, "DogC"));
        Collections.sort(list, new Comparator<Dog>() {

            @Override
            public int compare(Dog o1, Dog o2) {
                return o2.age - o1.age;
            }
        });
        System.out.println("给狗狗按照年龄倒序:" + list);
        Collections.sort(list, new Comparator<Dog>() {

            @Override
            public int compare(Dog o1, Dog o2) {
                return o1.name.compareTo(o2.name);
            }
        });
        System.out.println("给狗狗按名字字母顺序排序:" + list);
    }
}

2.分组

使用 Comparator 和 for 循环处理列表,来进行分类;通过调用者实现Comparator接口的比较逻辑,来告诉程序应该怎么比较,通过比较之后得结果来进行分组。比如生活中的拳击比赛,会有公斤级的概念,那么程序中应该实现的处理逻辑是只要两个人的体重在同一个区间则为同一组公斤级的选手。下面例子中分别按照狗狗的颜色和体重级别两个维度来进行分组,因此分组的核心逻辑其实就是比较逻辑。相面我抽了一个工具方法:dividerList,第一个参数为需要处理的数据源,第二参数是分组时的比较逻辑。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

public class GroupTest {
    class Apple {
        public String color;
        public int weight;

        public Apple(String color, int weight) {
            super();
            this.color = color;
            this.weight = weight;
        }

        @Override
        public String toString() {
            return "Apple [color=" + color + ", weight=" + weight + "]";
        }
    }

     public static <T> List<List<T>> divider(Collection<T> datas, Comparator<? super T> c) {
        List<List<T>> result = new ArrayList<List<T>>();
        for (T t : datas) {
            boolean isSameGroup = false;
            for (int j = 0; j < result.size(); j++) {
                if (c.compare(t, result.get(j).get(0)) == 0) {
                    isSameGroup = true;
                    result.get(j).add(t);
                    break;
                }
            }
            if (!isSameGroup) {
                // 创建
                List<T> innerList = new ArrayList<T>();
                result.add(innerList);
                innerList.add(t);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<Apple> list = new ArrayList<>();
        list.add(new GroupTest().new Apple("红", 205));
        list.add(new GroupTest().new Apple("红", 131));
        list.add(new GroupTest().new Apple("绿", 248));
        list.add(new GroupTest().new Apple("绿", 153));
        list.add(new GroupTest().new Apple("黄", 119));
        list.add(new GroupTest().new Apple("黄", 224));
        List<List<Apple>> byColors = divider(list, new Comparator<Apple>() {

            @Override
            public int compare(Apple o1, Apple o2) {
                // 按颜色分组
                return o1.color.compareTo(o2.color);
            }
        });
        System.out.println("按颜色分组" + byColors);
        List<List<Apple>> byWeight = divider(list, new Comparator<Apple>() {

            @Override
            public int compare(Apple o1, Apple o2) {
                // 按重量级
                return (o1.weight / 100 == o2.weight / 100) ? 0 : 1;
            }
        });
        System.out.println("按重量级分组" + byWeight);
    }
}

排序和分组的区别在于:
排序时,两个对象比较的结果有三种:大于,等于,小于。
分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)

五、Java Comparator.comparing | 提取对象属性,按照指定规则排序

comparing 是比较器功能接口的静态方法。
Comparator.comparing 方法在 Java 8 中被引入。
Comparator.comparing 接受一个函数,该函数从给定类型中提取一个可比较的排序键,并返回一个通过该排序键进行比较的比较器。

1、Comparator.comparing

comparing 方法声明一:

static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)

需要传递一个函数,它将从一个类型 T 中提取一个可比较的排序键,并返回一个通过该排序键进行比较的比较器。

示例代码:

Comparator<Student> nameComparator = Comparator.comparing(Student::getName);

comparing 方法声明二:

static <T,U> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)

需要传递一个函数 (Function ) 和一个比较器 (Comparator)。该方法将从一个类型 T 中提取一个排序键,并返回一个比较器,使用指定的比较器对该排序键进行比较。

示例代码:

Comparator<Student> nameComparator = Comparator.comparing(Student::getName, (s1, s2) -> s2.compareTo(s1));

对于 int、long 和 double 数据类型的排序键,比较器分别有 comparingInt、comparingLong 和 comparingDouble 方法。

实现 Comparable 接口的类,并定义 compareTo 方法。

School.java

public class School implements Comparable<School> {
    private int code;
    private String name;

    public School(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    @Override
    public int compareTo(School s) {
        return s.name.compareTo(name);
    }
}

Student.java

import java.util.Arrays;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private int age;
    private long homeDistance;
    private double weight;
    private School school;

    public static List<Student> getStudentList() {
        Student s1 = new Student("Ram", 18, 3455, 60.75, new School(101, "PQ College"));
        Student s2 = new Student("Shyam", 22, 3252, 65.80, new School(103, "RS College"));
        Student s3 = new Student("Mohan", 19, 1459, 65.20, new School(102, "AB College"));
        Student s4 = new Student("Mahesh", 20, 4450, 70.25, new School(104, "CD College"));
        List<Student> list = Arrays.asList(s1, s2, s3, s4);
        return list;
    }
}

ComparingDemo.java

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparingDemo {
    public static void main(String[] args) {
        List<Student> list = Student.getStudentList();

        Comparator<Student> schoolComparator1 = Comparator.comparing(Student::getSchool);
        Collections.sort(list, schoolComparator1);
        list.forEach(s -> System.out.print(s.getName() + "-" + s.getSchool().getName() + " | "));
        System.out.println("\n-------------------");

        Comparator<Student> schoolComparator2 = Comparator.comparing(Student::getSchool, (sch1, sch2) -> sch1.getCode() - sch2.getCode());
        Collections.sort(list, schoolComparator2);
        list.forEach(s -> System.out.print(s.getName() + "-" + s.getSchool().getCode() + " | "));
        System.out.println("\n-------------------");

        Comparator<Student> nameComparator1 = Comparator.comparing(Student::getName);
        Collections.sort(list, nameComparator1);
        list.forEach(s -> System.out.print(s.getName() + " "));
        System.out.println("\n-------------------");

        Comparator<Student> nameComparator2 = Comparator.comparing(Student::getName, (s1, s2) -> s2.compareTo(s1));
        Collections.sort(list, nameComparator2);
        list.forEach(s -> System.out.print(s.getName() + " "));
    }
}

在上面的例子中,使用 Collections.sort 对集合进行排序。也可以使用 Stream.sorted、List.sort 和 Arrays.sort 来使用比较器对集合进行排序。

2、Comparator.comparingInt

comparingInt 方法声明:

static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)

它接受一个从类型 T 中提取一个 int 排序键的函数,并返回一个通过该排序键进行比较的比较器。

ComparingIntDemo.java

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparingIntDemo {
  public static void main(String[] args) {
    List<Student> list = Student.getStudentList();
    
    Collections.sort(list, Comparator.comparingInt(Student::getAge));
    list.forEach(s->System.out.print(s.getAge() + " "));    
  }
}

输出

18 19 20 22

3、Comparator.comparingLong

comparingLong 方法声明:

static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)

它接受一个从类型 T 中提取一个 long 排序键的函数,并返回一个通过该排序键进行比较的比较器。

ComparingLongDemo.java

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparingLongDemo {
  public static void main(String[] args) {
    List<Student> list = Student.getStudentList();
    
    Collections.sort(list, Comparator.comparingLong(Student::getHomeDistance));
    list.forEach(s->System.out.print(s.getHomeDistance() + " "));           
  }
}

输出

1459 3252 3455 4450

4、Comparator.comparingDouble

comparingDouble 方法声明:

static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)

它接受一个从类型 T 中提取一个 double 排序键的函数,并返回一个通过该排序键进行比较的比较器。

ComparingDoubleDemo.java

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparingDoubleDemo {
  public static void main(String[] args) {
    List<Student> list = Student.getStudentList();
    
    Collections.sort(list, Comparator.comparingDouble(Student::getWeight));
    list.forEach(s->System.out.print(s.getWeight() + " "));           
  }
}

输出
60.75 65.2 65.8 70.25

一、概述

Comparable 和 Comparator 在 java 中都是用于来比较数据大小。实现 Comparable 接口需要重写 compareTo 方法,实现Comparator 方法需要重写 compare 方法。 这两个方法返回值都是 int 类型,根据返回值来判断比较对象的大小,从而实现排序。

二、用法

Comparable 需要实现,重写 compareto 方法

public int compareTo(T o);

从小到大:this.getXXX - o.getXXX()
从大到小:o.getXXX - this.getXXX

Comparetor 接口,重写 compare() 方法

public static int compare(double d1, double d2) {}

从小到大:return d1 - d2;
从大到小: return d2 - d1;

再加一种可直接排序的方法,我们使用User对象来进行验证

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer age;
    private Double money;
    private String name;
}
public class CompareterTest {
    public static void main(String[] args) {
        List<User> list = new ArrayList<>();
        list.add(new User(1, 1.0, "c"));
        list.add(new User(1, 2.0, "a"));
        list.add(new User(1, 2.0, "b"));
        list.add(new User(3, 2.0, "a"));
        list.add(new User(3, 1.0, "c"));
        list.add(new User(3, 3.0, "b"));
        list.add(new User(2, 1.0, "b"));
        System.out.println(list);
        // 在集合工具类排序时可使用thenComparing方法进行多字段排序
        Collections.sort(list, Comparator.comparingInt((User::getAge))
                .thenComparing(User::getMoney)
                .thenComparing(User::getName));
        Collections.sort(list, (a, b) -> {
            // 按年龄倒叙
            return b.getAge() - a.getAge();
        });
        System.out.println(list);
    }
}

也可在对象中实现 Comparetor 接口的 compare 方法进行自定义排序。

@Data 使用
@Data 注解的主要作用是提高代码的简洁,使用这个注解可以省去代码中大量的 get()、 set()、 toString() 等方法;

引入 lombok
要使用 @Data 注解要先引入 lombok,lombok 是什么,它是一个工具类库,可以用简单的注解形式来简化代码,提高开发效率。

在 maven 中添加依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>
</dependency>

用 @Data 的写法:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private String address;
    private Integer age;
    private String hobbit;
    private String phone;
}

常用的几个注解:
@Data : 注在类上,提供类的 get、set、equals、hashCode、canEqual、toString 方法
@AllArgsConstructor : 注在类上,提供类的全参构造
@NoArgsConstructor : 注在类上,提供类的无参构造
@Setter : 注在属性上,提供 set 方法
@Getter : 注在属性上,提供 get 方法
@EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
@Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log

原理
Lombok本质上就是一个实现了“JSR 269 API” 的程序。在使用 javac 的过程中,它产生作用的具体流程如下:

javac 对源代码进行分析,生成了一棵抽象语法树(AST)
运行过程中调用实现了“JSR 269 API”的 Lombok 程序
此时 Lombok 就对第一步骤得到的 AST 进行处理,找到 @Data 注解所在类对应的语法树(AST),然后修改该语法树(AST),增加 getter 和 setter 方法定义的相应树节点
javac使用修改后的抽象语法树(AST)生成字节码文件,即给 class 增加新的节点(代码块)

优缺点
优点:
能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等 方法,提高了一定的开发效率
让代码变得简洁,不用过多的去关注相应的方法
属性做修改时,也简化了维护为这些属性所生成的 getter/setter 方法等

缺点:
不支持多种参数构造器的重载
虽然省去了手动创建 getter/setter 方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度
像 lombok 这种插件,已经不仅仅是插件了,它在编译器编译时通过操作 AST(抽象语法树)改变字节码生成,变相的说它就是在改变 java 语法,它改变了你编写源码的方式,它不像 spring 的依赖注入一样是运行时的特性,而是编译时的特性。如果一个项目有非常多这样的插件,会极大的降低阅读源代码的舒适度。
lombok 只是省去了一些人工生成代码的麻烦,但是这些 getter/setter 等等的方法,用 IDE 的快捷键也可很方便的生成。况且,有时通过给g etter/setter 加一点点业务代码(但通常不建议这么加),能极大的简化某些业务场景的代码。