目录
3.2. boolean equals(Object obj)
1. 用处
用于对对象集合进行总排序:
- 传递给排序方法(如 Collections.sort / Arrays.sort),以便精确控制排序顺序。
- 用于控制某些数据结构的排序。
- 为没有 natural ordering 的对象集合提供排序。
2. 规范
- 实现此接口的对象列表可以通过
Collections.sort和Arrays.sort自动排序。无序指定比较器。 - 当且仅当类 C 的 e1 和 e2 的 e1.compareTo(e2) == 0 的布尔值与 e1.equals(e2) 的布尔值相同时,类 C 的自然排序被认为与等价一致。
- 强烈建议
a.equals(b)和a.compareTo(b) == 0的逻辑相同,否则将会发生奇怪的错误。 - 如果将比较器作用于一个可序列化的数据结构,如
TreeSet和TreeMap,则实现比较器接口时也需要实现 Serializable 接口进行序列化。
3. 比较器功能方法
3.1. int compare(T o1,T o2)
用来比较两个参数的大小:当 o1 小于、等于、大于 o2 时,分别返回负值、零、正值。
其实现方式有两种:使用 lambda 表达式定义、自定义 compare 实现比较器。
实现一:使用 lamdba 表达式
定义方式:
// 通过Student的age属性进行比较
Comparator<Student> ageComp =(s1 , s2) -> s1.getAge() - s2.getAge();
// 通过Student的name属性进行比较
Comparator<Student> nameComp = (s1 , s2) -> s1.getName() - s2.getName();
使用示例:
import java.util.Comparator;
import java.util.List;
public class CompareDemo {
public static void main(String[] args) {
List<Student> list = Student.getStudentList();
System.out.println("--- Sort Students by age ---");
Comparator<Student> ageComp = (s1, s2) -> s1.getAge() - s2.getAge();
list.sort(ageComp);
list.forEach(s -> System.out.println(s));
System.out.println("--- Sort Students by name ---");
Comparator<Student> nameComp = (s1, s2) -> s1.getName().compareTo(s2.getName());
list.sort(nameComp);
list.forEach(s -> System.out.println(s));
}
}
实现二:自定义 compare 实现比较器
定义方式:
class AgeComparator implements Comparator<Strudent> , Serializable{
private static final long serialVersionUID = 1L;
@Override
public int compare(Student s1, Student s2){
return s1.getAge - s2.getAge;
}
}
3.2. boolean equals(Object obj)
重写了 Object 的 equals 方法,用于比较两个比较器是否相等;
当 obj 也是一个比较器,并且他的排序于此比较器相同时,才会返回 true。也就是说,comp1.equals(comp2)意味着对于任意的 o1,o2 都有 sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2)) ,其中的 sgn 是 java 中的符号函数,将正数返回 1,负数返回 -1,0 依然返回 0;
4. 比较器的使用
可以将比较器与 Stream.sorted/Collections.sort/List.sort/Arrays.sort方法相结合来使用。
4.1. Stream.sorted
Stream.sorted 返回一个由这个流的元素组成的流,根据提供的比较器进行排序。
import java.util.Comparator;
import java.util.List;
public class CompareDemoStreamSorted {
public static void main(String[] args) {
List<Student> list = Student.getStudentList();
System.out.println("--- Sort Students by age ---");
Comparator<Student> ageComp = (s1, s2) -> s1.getAge() - s2.getAge();
list.stream().sorted(ageComp).forEach(s -> System.out.println(s));
System.out.println("--- Sort Students by name ---");
Comparator<Student> nameComp = (s1, s2) -> s1.getName().compareTo(s2.getName());
list.stream().sorted(nameComp).forEach(s -> System.out.println(s));
}
}
4.2. Collections.sort
Collections.sort 根据给定的比较器实例对指定的列表进行排序。
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CompareDemoCollectionsSort {
public static void main(String[] args) {
List<Student> list = Student.getStudentList();
System.out.println("--- Sort Students by age ---");
Comparator<Student> ageComp = (s1, s2) -> s1.getAge() - s2.getAge();
Collections.sort(list, ageComp);
list.forEach(s -> System.out.println(s));
System.out.println("--- Sort Students by name ---");
Comparator<Student> nameComp = (s1, s2) -> s1.getName().compareTo(s2.getName());
Collections.sort(list, nameComp);
list.forEach(s -> System.out.println(s));
}
}
4.3. List.sort
List.sort 根据给定的比较器实例对这个列表进行排序。
import java.util.Comparator;
import java.util.List;
public class CompareDemoListSort {
public static void main(String[] args) {
List<Student> list = Student.getStudentList();
System.out.println("--- Sort Students by age ---");
Comparator<Student> ageComp = (s1, s2) -> s1.getAge() - s2.getAge();
list.sort(ageComp);
list.forEach(s -> System.out.println(s));
System.out.println("--- Sort Students by name ---");
Comparator<Student> nameComp = (s1, s2) -> s1.getName().compareTo(s2.getName());
list.sort(nameComp);
list.forEach(s -> System.out.println(s));
}
}
5. 常见方法
5.1. reversed()
- 返回一个比较器,该比较器的排序与此比较器相反。
5.2. thenComparing()
当两个对象通过主排序规则比较结果相等时,thenComparing 方法会提供一个次级排序规则来进一步比较。这种链式调用可以实现多级排序(先按照第一个规则排序,如果相等再按照第二个规则排序)
thenComparing 的重载方法:
- thenComparing(Comparator<? super T> other)
-
- 接受另一个 Comparator 作为次级排序规则。
- thenComparing(Function<? super T, ? extends U> keyExtractor)
-
- 接受一个函数,从对象中提取键值,然后使用自然排序。
- thenComparing(Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator)
-
- 接受一个函数和一个比较器,先提取键值,再使用指定的比较器进行排序。
- thenComparingInt(ToIntFunction<? super T> keyExtractor)
-
- 专门用于比较整数键值,效率更高。 ‘
代码示例:
// Person类
class Person {
String name;
int age;
double height;
public Person(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", height=" + height + '}';
}
}
//示例
import java.util.*;
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30, 5.4),
new Person("Bob", 25, 5.8),
new Person("Charlie", 30, 5.4),
new Person("David", 30, 5.9),
new Person("Eve", 25, 5.8)
);
// 多级排序:先按年龄,再按身高,再按姓名
Comparator<Person> comparator = Comparator
.comparingInt((Person p) -> p.age) // 主排序:按年龄升序
.thenComparingDouble(p -> p.height) // 次排序:按身高升序
.thenComparing(p -> p.name); // 再次排序:按姓名字典序
// 排序
people.sort(comparator);
// 输出结果
people.forEach(System.out::println);
}
}
重载方法 3 的代码示例:
class Product {
String name;
double price;
double rating;
public Product(String name, double price, double rating) {
this.name = name;
this.price = price;
this.rating = rating;
}
@Override
public String toString() {
return "Product{name='" + name + "', price=" + price + ", rating=" + rating + '}';
}
}
@Test
public void test(){
List<Product> products = Arrays.asList(
new Product("Laptop", 1200.0, 4.5),
new Product("Phone", 800.0, 4.8),
new Product("Tablet", 800.0, 4.4),
new Product("Monitor", 300.0, 4.8),
new Product("Keyboard", 300.0, 4.5),
new Product("Mouse", 300.0, 4.5)
);
// 定义排序规则
Comparator<Product> comparator = Comparator
// 主排序规则:按价格升序
.comparingDouble((Product p) -> p.price)
// 次排序规则:按评分降序
.thenComparing(
(Product p) -> p.rating,
(rating1, rating2) -> Double.compare(rating2, rating1)
)
// 再次排序规则:按名称字典序升序
.thenComparing(p -> p.name);
// 对商品列表排序
products.sort(comparator);
// 输出排序后的结果
products.forEach(System.out::println);
}
5.3. <静态>reverseOrder()
返回一个比较器,这个比较器的排序规则是自然排序的逆序。
5.4. <静态>naturalOrder()
返回一个比较器,这个比较器的排序规则是自然排序。
5.5. <静态>nullsFirst()
返回一个对空值友好的比较器,她会认为 null 小于非空值,即排序后 null 值处于列表的最前方。
5.6. <静态>nullsLast()
返回一个对空值友好的比较器,她会认为 null 大于非空值,即排序后 null 值处于列表的最后方。
5.7. <静态>comparing()
接受一个函数,该函数从类型 T 中提取 Comparable 排序键,并返回一个按该排序键进行比较的 Comparator<T>.
eg:
Comparator<Student> nameComparator = Comparator.comparing(Student::getName);
/**
这个排序器用于Student类,用于按照name的字典序排序。
*/
- comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
接受一个从类型 T 中提取排序键的函数,并返回一个使用指定 Comparator 按该排序键进行比较的 Comparator<T>.
- comparingDouble(ToDoubleFunction<? super T> keyExtractor)
作用同 1,不过要求提取出的排序键必须是 double 类型。
- comparingInt(ToIntFunction<? super T> keyExtractor)
作用同 1,不过要求提取出的排序键必须是 int 类型。
- comparingLong(ToLongFunction<? super T> keyExtractor)
作用同 1,不过要求提取出的排序键必须是 Long 类型。
1万+

被折叠的 条评论
为什么被折叠?



