Comparator 使用详解及部分代码解析
最近使用Comparator 比较多,觉得挺有意思的,简单好用,方便。记录一下;
1.介绍
Comparator 里面的方法,我们可以分成几大类。下面的测试代码,也是根据这几大类,测试其中部分方法,剩余方法类似,就不在使用。
- compare - 正常比较
- naturalOrder - 自然比较,根据实体类定义的Comparable
- nullsFirst、nullsLast - 将null值放在第一个或者最后一个
- comparing、comparingLong、comparingInt、comparingDouble - 常用比较方法,可以指定参数类型
- reversed、reverseOrder - 反转
- thenComparing、thenComparingDouble、thenComparingInt、thenComparingLong - 多次比较
其中comparing 有一个重载方法thenComparing,有两个重载方法
2.测试
package com.study.testCompare;import org.junit.Test;import java.math.BigDecimal;
import java.util.*;public class ComparatorTest {@Testpublic void testCompare() {List personList = new ArrayList<>();personList.add(new Person("a", new BigDecimal(12), 170));personList.add(new Person("b", new BigDecimal(24), 175, new Student(27)));personList.add(new Person("c", new BigDecimal(12), 177));personList.add(new Person("a", new BigDecimal(12), 177));personList.add(new Person("b", new BigDecimal(54), 174, new Student(19)));// naturalOrderSystem.out.println("naturalOrder : ");personList.sort(Comparator.naturalOrder());personList.forEach(System.out::println);// comparing 1.0Optional optional = personList.stream().max(Comparator.comparing(Person::getAge));System.out.println("comparing 1.0 : get max age " + optional.get().toString() + "\n");// comparing 2.1optional = personList.stream().max(Comparator.comparing(Person::getName, Comparator.reverseOrder()));System.out.println("comparing 2.1 : get min name " + optional.get().toString() + "\n");// comparing 2.2optional = personList.stream().max(Comparator.comparing(Person::getName, String::compareTo));System.out.println("comparing 2.2 : get max name " + optional.get().toString() + "\n");// comparing 2.3optional = personList.stream().max(Comparator.comparing(Person::getStudent, (o1, o2) -> new Student().compare(o1, o2)));System.out.println("comparing 2.3 : get max student.age " + optional.get().toString() + "\n");// thenComparing 1.0System.out.println("thenComparing 1.0 : ");personList.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getHeight));personList.forEach(System.out::println);// thenComparing 2.0System.out.println("thenComparing 2.0 : ");personList.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getHeight).thenComparing(Person::getName));personList.forEach(System.out::println);// 升序System.out.println("升序 : ");personList.sort(Comparator.comparingInt(Person::getHeight));personList.forEach(System.out::println);// 降序System.out.println("降序 : ");personList.sort(Comparator.comparingInt(Person::getHeight).reversed());personList.forEach(System.out::println);// nullsLastSystem.out.println("nullsLast : ");personList.sort(Comparator.nullsLast(Comparator.comparing(Person::getName)));personList.forEach(System.out::println);// nullsLastSystem.out.println("nullsLast : ");personList.sort(Comparator.nullsLast(Comparator.comparing(Person::getName)));personList.forEach(System.out::println);}}
package com.study.testCompare;import lombok.Data;import java.math.BigDecimal;
import java.util.Comparator;@Data
public class Person implements Comparable {private String name;private BigDecimal age;private Integer height;private Student student;public Person(String name, BigDecimal age, Integer height) {this.name = name;this.age = age;this.height = height;this.student = new Student(0);}public Person(String name, BigDecimal age, Integer height, Student student) {this.name = name;this.age = age;this.height = height;this.student = student;}@Overridepublic int compareTo(Object o) {Person p1 = (Person) o;if (this.age.equals(p1.age)) {return p1.height - this.height;}return this.age.compareTo(p1.age);}
}@Data
class Student implements Comparator {private int age;public Student() {}public Student(int age) {this.age = age;}@Overridepublic int compare(Object o1, Object o2) {Student p1 = (Student) o1;Student p2 = (Student) o2;int result = Integer.compare(p1.age, p2.age);result = result == 0 ? ((p1.age > p2.age) ? 1 : -1) : result;return result;}
}
3.源码
package java.util;import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;/*** 注解过长,不做翻译*/
@FunctionalInterface
public interface Comparator {/*** 最常用的的方法* o1 = o2 : return 0;* o1 > o2 : return 1;* o1 < o2 : return -1;*/int compare(T o1, T o2);/*** equals 方法*/boolean equals(Object obj);/*** 排序反转*/default Comparator reversed() {return Collections.reverseOrder(this);}/*** 连续 比较,比如先比较一个人的年龄,在比较一个人的身高,在比较一个人的体重* @since 1.8*/default Comparator thenComparing(Comparator super T> other) {Objects.requireNonNull(other);return (Comparator & Serializable) (c1, c2) -> {int res = compare(c1, c2);return (res != 0) ? res : other.compare(c1, c2);};}/*** 连续 比较,入参不同,自定义compara* @since 1.8*/default Comparator thenComparing(Function super T, ? extends U> keyExtractor,Comparator super U> keyComparator){return thenComparing(comparing(keyExtractor, keyComparator));}/*** 连续 比较,入参不同* @since 1.8*/default > Comparator thenComparing(Function super T, ? extends U> keyExtractor){return thenComparing(comparing(keyExtractor));}/*** 连续 比较,指定Int类型* @since 1.8*/default Comparator thenComparingInt(ToIntFunction super T> keyExtractor) {return thenComparing(comparingInt(keyExtractor));}/*** 连续 比较,指定Long类型* @since 1.8*/default Comparator thenComparingLong(ToLongFunction super T> keyExtractor) {return thenComparing(comparingLong(keyExtractor));}/*** 连续 比较,指定Double类型* @since 1.8*/default Comparator thenComparingDouble(ToDoubleFunction super T> keyExtractor) {return thenComparing(comparingDouble(keyExtractor));}/*** 反转排序* @since 1.8*/public static > Comparator reverseOrder() {return Collections.reverseOrder();}/*** 自然排序(实体类需要实现 Comparable)* @since 1.8*/@SuppressWarnings("unchecked")public static > Comparator naturalOrder() {return (Comparator) Comparators.NaturalOrderComparator.INSTANCE;}/*** 如果有空数据,放在第一个* @since 1.8*/public static Comparator nullsFirst(Comparator super T> comparator) {return new Comparators.NullComparator<>(true, comparator);}/*** 如果有空数据,放在最后一个* @since 1.8*/public static Comparator nullsLast(Comparator super T> comparator) {return new Comparators.NullComparator<>(false, comparator);}/*** 正常排序(正序,需要实现Comparator),入参两个参数。第二个为Comparator* @since 1.8*/public static Comparator comparing(Function super T, ? extends U> keyExtractor,Comparator super U> keyComparator){Objects.requireNonNull(keyExtractor);Objects.requireNonNull(keyComparator);return (Comparator & Serializable)(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),keyExtractor.apply(c2));}/*** 正常排序(正序,需要实现Comparator)。一个参数* @since 1.8*/public static > Comparator comparing(Function super T, ? extends U> keyExtractor){Objects.requireNonNull(keyExtractor);return (Comparator & Serializable)(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));}/*** 正常排序 —— int* @since 1.8*/public static Comparator comparingInt(ToIntFunction super T> keyExtractor) {Objects.requireNonNull(keyExtractor);return (Comparator & Serializable)(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));}/*** 正常排序 —— long* @since 1.8*/public static Comparator comparingLong(ToLongFunction super T> keyExtractor) {Objects.requireNonNull(keyExtractor);return (Comparator & Serializable)(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));}/*** * 正常排序 —— double* @since 1.8*/public static Comparator comparingDouble(ToDoubleFunction super T> keyExtractor) {Objects.requireNonNull(keyExtractor);return (Comparator & Serializable)(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));}
}
4.解析部分方法
源码:
/*** 正常排序(正序,需要实现Comparator)。一个参数* @since 1.8*/public static > Comparator comparing(Function super T, ? extends U> keyExtractor){Objects.requireNonNull(keyExtractor);return (Comparator & Serializable)(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));}
使用:
// comparing 1.0Optional optional = personList.stream().max(Comparator.comparing(Person::getAge));System.out.println("comparing 1.0 : max age " + optional.get().toString() + "\n");
通过debug可知,最终源码中,c1和c2是Person对象,在比较的时候,调用了Integer的compareTo。
那么可以知道 keyExtractor.apply(c1) = c1.getAge() ,keyExtractor.apply(c2) = c2.getAge() 。而且源码中明确指出:Function super T, ? extends U> keyExtractor
其中:
T为传入类型U为返回类型
所以我们使用lamble后,传入的Person为T,getAge为U。所以keyExtractor.apply返回的就是Integer类型的age。最终调用对应包装类型的compareTo实现比较
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
