Comparator比较器

简介

为什么写?


  • comparatorjavase中的接口,位于java.util包下,该接口抽象度极高,有必要掌握该接口的使用
  • 大多数文章告诉大家comparator是用来排序,但我想说排序是comparator能实现的功能之一,他不仅限于排序

接口功能


Comparator接口代表一个比较器,比较器具有可比性!平时我们大多数都是使用改接口(Comparator)实现对集合,排序。这是

因为JAVASE数组工具类和集合工具类中提供的sort方法sort就是使用Comparator接口来处理排序的,但是Comparator接口并不只是

用来排序的,下面是JAVASE一些使用到Comparator接口的地方:

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

使用场景


什么场景需要做比较,那么什么场景就是Comparator接口的用武之地,我总结的两个场景:

  1. 排序,需要比较两个对象谁排在前谁排在后(排序也可以让类实现Comparable接口,实现后该类的实例也具有排序能力)。
  2. 分组,需要比较两个对象是否是属于同一组。

排序场景

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

条件排序:公共代码

public class SortTest {

    @Data
@AllArgsConstructor
@ToString
class Dog{ //内部类
public int age;
public String name;
public String num;
} List<Dog> list= new ArrayList<Dog>(){
{
add(new Dog(5, "DogA","001"));
add(new Dog(5, "DogB","002"));
add(new Dog(5, "DogC","003"));
add(new Dog(9, "DogA","004"));
add(new Dog(35, "DogF","005"));
add(new Dog(74, "Dogg","006"));
}
};
}

单一条件排序

Comparator实现排序(按照年龄,名字)

   /**
*单一条件排序
*/ @Test
public void test1(){
//按照年龄排序
Collections.sort(list, new Comparator<Dog>() {
//实现compare(T o1, To2) 方法,返回正数,零,负数各代表大于,等于小于
@Override
public int compare(Dog o1, Dog o2) {
//return o2.age - o1.age; //排序规则----升序
return String.valueOf(o1.getAge()).compareTo(String.valueOf(o2.getAge())); //compareTo()传String
}
});
System.out.println("给狗狗按照年龄倒序:"+list);
} @Test
public void test2(){
//按照名字排序
Collator comparator = Collator.getInstance(Locale.CANADA); Collections.sort(list, new Comparator<Dog>() { @Override
public int compare(Dog o1, Dog o2) {
// return o1.name.compareTo(o2.name);
return comparator.compare(o1.getName(),o2.getName());
}
});
System.out.println("给狗狗按名字字母顺序排序:"+list);
}

Lambda优化实现排序

    /**
*使用Lambda表达式优化比较器代码(单一条件排序)
*/
@Test
public void test3() {
//对学生集合按年龄进行排序
Collections.sort(list,(s1, s2) -> (s1.getAge() - s2.getAge()) );
}

多条件排序

Comparator实现排序(按照年龄和名字)

 	/**
*多条件排序
*/
@Test
public void test4() { Collections.sort(list,new Comparator<Dog>() { @Override
public int compare(Dog s1, Dog s2) {
int flag;
// 首选按年龄升序排序
flag = s1.getAge()-s2.getAge();
if(flag==0){
// 如果年龄按编号降序排序
flag = s2.getNum().compareTo(s1.getNum());
}
return flag;
}
});
list.forEach(System.out::println);
}

Lambda优化实现多条件排序

       /**
*多条件排序 ----使用lambda表达式优化
*/
@Test
public void test5() {
Collections.sort(list,(s1,s2)->{
int flag;
// 首选按年龄升序排序
flag = s1.getAge()-s2.getAge(); // 方案一、判断是否为空 --- 为空执行lambda表达式,返回一个对象
flag = Optional.ofNullable(flag == 0 ? null: flag).orElseGet(() -> s2.getNum().compareTo(s1.getNum())); //方案二、
if(flag==0){
// 如果年龄按编号降序排序
flag =s2.getNum().compareTo(s1.getNum());
}
//最终返回
return flag;
});
list.forEach(System.out::println);
}

自定义条件排序

自定义条件排序公共代码


    /**
*自定义条件排序
*/
//定义排序规则 通过asList()方法将数组转为list集合
String[] order = {"语文","数学","英语","物理","化学","生物","政治","历史","地理","总分"};
final List<String> definedOrder = Arrays.asList(order); //需要排序的数据
List<String> listClass = new ArrayList<String>(){
{
add("总分");
add("英语");
add("政治");
add("总分");
add("数学");
}
};

自定义条件排序方案一 Comparator

    //自定义条件排序方案一
@Test
public void test6(){ Collections.sort(listClass,new Comparator<String>() { @Override
public int compare(String o1, String o2) {
//int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引。
int io1 = definedOrder .indexOf(o1);
int io2 = definedOrder .indexOf(o2);
return io1-io2;
}
}); for(String s:listClass){
System.out.print(s+" ");
}
//打印结果:数学 英语 政治 总分 总分
}

自定义条件排序方案二 Lambda

    //自定义条件排序方案二 使用Lambda表达式优化比较器代码
@Test
public void test7(){
Collections.sort(listClass,(s1,s2)->definedOrder.indexOf(s1) - definedOrder.indexOf(s2));
listClass.forEach(System.out::print);
}

分组场景


使用Comparatorfor循环处理列表,来进行分类;通过调用者实现Comparator接口的比较逻辑,来告诉程序应该怎么比较,通过比较之后得结果来进行分组。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面例子中分别按照狗狗的颜色和体重级别两个维度来进行分组,因此分组的核心逻辑其实就是比较逻辑。相面我抽了一个工具方法:dividerList,第一个参数为需要处理的数据源,第二参数是分组时的比较逻辑。

公共代码

  @Data
@AllArgsConstructor
@ToString
class Apple {
public String color;
public int weight;
}
List<Apple> list = new ArrayList<Apple>(){
{
add(new Apple("红", 205));
add(new Apple("红", 131));
add(new Apple("绿", 248));
add(new Apple("绿", 22));
add(new Apple("黄", 119));
add(new Apple("黄", 224));
add(new Apple("白", 2024));
}
}; /**
* 是否为同一组的判断标准 参数一:需要处理的数据源 datas,参数二分组时的比较逻辑c
*/
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;
}

Comparator实现按颜色分组

    @Test
public void test1(){
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);
}

Lambda优化按颜色分组

    /**
*使用lambda优化(按照颜色分组)
*/
@Test
public void test1_1() {
//按照颜色重量级分组
divider_Lambda(list, (o1, o2) -> o1.color.compareTo(o2.color)).forEach(System.out::println);
}

Comparator实现按分组

    @Test
public void test2(){
//按照重量级进行分组
List<List<Apple>> byWeight = divider(list, new Comparator<Apple>() { @Override
public int compare(Apple o1, Apple o2) {
// 按重量级
return (o1.getWeight() / 100 == o2.getWeight() / 100) ? 0 : 1;
}
});
byWeight.forEach(x-> System.out.println("按照总量分组:"+x));
//System.out.println("按重量级分组" + byWeight);
}

Lambda优化按重量级分组

    /**
*使用lambda优化(按照重量级进行分组)
*/
@Test
public void test2_1() {
//按照颜色分组
divider_Lambda(list, (o1, o2) -> (o1.getWeight() / 100 == o2.getWeight() / 100) ? 0 : 1).forEach(System.out::println);
}

Comparator接口常用的方法

公共代码

实体类

Persons实体类

package com.zy.pagehelper.model;

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor; import java.math.BigDecimal; @Data
@NoArgsConstructor
@Builder
public class Persons implements Comparable {
private String name;
private BigDecimal age;
private Integer height;
private Student student; public Persons(String name, BigDecimal age, Integer height) {
this.name = name;
this.age = age;
this.height = height;
this.student = new Student(0);
} public Persons(String name, BigDecimal age, Integer height, Student student) {
this.name = name;
this.age = age;
this.height = height;
this.student = student;
} @Override
public int compareTo(Object o) {
Persons p1 = (Persons) o; if (this.age.equals(p1.age)) {
return p1.height - this.height;
}
return this.age.compareTo(p1.age);
}
}

Student实体类

package com.zy.pagehelper.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Comparator; @Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Comparator { private int age; @Override
public 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;
}
}

公共集合

    Persons persons = new Persons();
List<Persons> personList = new ArrayList<Persons>() {
{
add(new Persons("a", new BigDecimal(12), 170));
add(new Persons("b", new BigDecimal(24), 175, new Student(27)));
add(new Persons("c", new BigDecimal(12), 177));
add(new Persons("a", new BigDecimal(12), 177));
add(new Persons("b", new BigDecimal(54), 174, new Student(19)));
}
};

naturalOrder 方法


naturalOrder - 自然比较,根据实体类定义的Comparable进行比较!

示例代码:

    @Test
public void testNaturalOrder(){
// naturalOrder 自然比较,根据实体类定义的Comparable
System.out.println("naturalOrder : ");
personList.sort(Comparator.naturalOrder());
personList.forEach(System.out::println);
}

comparing方法


comparing、comparingLong、comparingInt、comparingDouble - 常用比较方法,可以指定参数类型

comparing方法参数是一个函数式接口keyExtractor,意识即为指定排序对象中的排序键,这里注意排序键这里标注了Comparable接口

comparing方法

    /**
* Accepts a function that extracts a {@link java.lang.Comparable
* Comparable} sort key from a type {@code T}, and returns a {@code
* Comparator<T>} that compares by that sort key.
*
* <p>The returned comparator is serializable if the specified function
* is also serializable.
*
* @apiNote
* For example, to obtain a {@code Comparator} that compares {@code
* Person} objects by their last name,
*
* <pre>{@code
* Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
* }</pre>
*/
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));
}

comparing方法参数是一个函数式接口keyExtractor,意识即为指定排序对象中的排序键,这里注意排序键这里标注了Comparable接口。

同时我们也可以看到有重载的comparing方法:

   /**
* Accepts a function that extracts a sort key from a type {@code T}, and
* returns a {@code Comparator<T>} that compares by that sort key using
* the specified {@link Comparator}.
*
* <p>The returned comparator is serializable if the specified function
* and comparator are both serializable.
*
* @apiNote
* For example, to obtain a {@code Comparator} that compares {@code
* Person} objects by their last name ignoring case differences,
*
* <pre>{@code
* Comparator<Person> cmp = Comparator.comparing(
* Person::getLastName,
* String.CASE_INSENSITIVE_ORDER);
* }</pre>
*/
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));
}

第二个参数也很好理解,提取完sort key之后,要定义关于这个key的Comparator,在注释中的例子也比较好理解。 这里有个小tips:在String类中,提供了一个实现Comparator接口的常量来标识不对语言敏感的字典序排序器。

 /**
* A Comparator that orders {@code String} objects as by
* {@code compareToIgnoreCase}. This comparator is serializable.
* <p>
* Note that this Comparator does <em>not</em> take locale into account,
* and will result in an unsatisfactory ordering for certain locales.
* The java.text package provides <em>Collators</em> to allow
* locale-sensitive ordering.
*
* @see java.text.Collator#compare(String, String)
* @since 1.2
*/
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L; public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
} /** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
} // 这里其实可以看到compareToIgnoreCase也是调用了这个实例的compare方法
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}

在Comparator接口中,也直接提供了具体类型的三个comparing方法:

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) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
} public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
}

测试示例代码:

    @Test
public void testComparing(){
//comparing、comparingLong、comparingInt、comparingDouble - 常用比较方法,可以指定参数类型 // comparing 1.0 比较集合中对象的年龄,取最大值
Optional<Persons> optional = personList.stream().max(Comparator.comparing(Persons::getAge));
System.out.println("comparing 1.0 : get max age " + optional.get().toString() + "\n"); // comparing 2.1
optional = personList.stream().max(Comparator.comparing(Persons::getName, Comparator.reverseOrder()));
System.out.println("comparing 2.1 : get min name " + optional.get().toString() + "\n"); // comparing 2.2
optional = personList.stream().max(Comparator.comparing(Persons::getName, String::compareTo));
System.out.println("comparing 2.2 : get max name " + optional.get().toString() + "\n"); // comparing 2.3 该方法多了一个参数 keyComparator ,keyComparator 是创建一个自定义的比较器。示例种:通过cmmpare()方法进行学生年龄比较,
optional = personList.stream().max(Comparator.comparing(Persons::getStudent, (o1, o2) -> new Student().compare(o1, o2)));
System.out.println("comparing 2.3 : get max student.age " + optional.get().toString() + "\n"); }
/*
打印结果
comparing 1.0 : get max age Persons(name=b, age=54, height=174, student=Student(age=19)) comparing 2.1 : get min name Persons(name=a, age=12, height=170, student=Student(age=0)) comparing 2.2 : get max name Persons(name=c, age=12, height=177, student=Student(age=0)) comparing 2.3 : get max student.age Persons(name=b, age=24, height=175, student=Student(age=27))
*/ // 升序 comparing方法的具体实现一comparingInt
System.out.println("升序 : ");
personList.sort(Comparator.comparingInt(Persons::getHeight));
personList.forEach(System.out::println); // 降序 comparing方法的具体实现二comparingInt
System.out.println("降序 : ");
personList.sort(Comparator.comparingInt(Persons::getHeight).reversed());
personList.forEach(System.out::println);

thenComparing方法


/**
* Returns a lexicographic-order comparator with another comparator.
* If this {@code Comparator} considers two elements equal, i.e.
* {@code compare(a, b) == 0}, {@code other} is used to determine the order.
*
* <p>The returned comparator is serializable if the specified comparator
* is also serializable.
*
* @apiNote
* For example, to sort a collection of {@code String} based on the length
* and then case-insensitive natural ordering, the comparator can be
* composed using following code,
*
* <pre>{@code
* Comparator<String> cmp = Comparator.comparingInt(String::length)
* .thenComparing(String.CASE_INSENSITIVE_ORDER);
* }</pre>
*/
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);
};
}

从方法名称上知道这是当比较相同时的使用的一个排序规则,这里需要注意看具体实现是会先调用比较器实例中的compare方法来进行比较一轮,当结果等于0的时候才会调用other这个比较器规则进行比较。比如下面的一个DOME:

List<String> strings = Arrays.asList("def", "abc", "hel", "world");
strings.sort(Comparator.comparingInt(String::length).reversed() //(1)
.thenComparing(String::compareToIgnoreCase) // (2)
.thenComparing(Comparator.reverseOrder()) // (3)这个比较器不会被应用 因为比较器(2)已经把结果比较出来了,并且没有相等的结果,这里不会再应用(3)比较器
); System.out.println(strings); // 输出[world, abc, def, hel]

当然因为有了 comparing方法的支持,所以也就有了下面两个thenComparing的重载方法

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

测试示例代码:

    @Test
public void test2(){
//根据第一个属性进行排序,如果相同则以此根据下一个thenComparing()中的属性进行排序 // thenComparing 1.0
System.out.println("thenComparing 1.0 : ");
personList.sort(Comparator.comparing(Persons::getAge));
personList.forEach(System.out::println); // thenComparing 1.1
System.out.println("thenComparing 1.1 : ");
personList.sort(Comparator.comparing(Persons::getAge).thenComparing(Persons::getHeight));
personList.forEach(System.out::println); // thenComparing 2.0
System.out.println("thenComparing 2.0 : ");
personList.sort(Comparator.comparing(Persons::getAge).thenComparing(Persons::getHeight).thenComparing(Persons::getName));
personList.forEach(System.out::println); }

nullsLast()/nullsFirst()


Comparator接口中有两个对null友好的比较器方法:

   /**
* Returns a null-friendly comparator that considers {@code null} to be
* less than non-null. When both are {@code null}, they are considered
* equal. If both are non-null, the specified {@code Comparator} is used
* to determine the order. If the specified comparator is {@code null},
* then the returned comparator considers all non-null values to be equal.
*
* <p>The returned comparator is serializable if the specified comparator
* is serializable.
*
* @param <T> the type of the elements to be compared
* @param comparator a {@code Comparator} for comparing non-null values
* @return a comparator that considers {@code null} to be less than
* non-null, and compares non-null objects with the supplied
* {@code Comparator}.
* @since 1.8
*/
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(true, comparator);
} // null比非null元素都大的
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(false, comparator);
}

这里是通过Comparators这个工厂类提供的NullComparator比较器实现的,看到注释有一条需要注意是如果不指定comparator参数,即传入null,那么所有的非null参数都会被视为相等。

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

测试示例代码

    @Test
public void testNulls() { // nullsLast
System.out.println("nullsLast : ");
personList.sort(Comparator.nullsLast(Comparator.comparing(Persons::getName)));
personList.forEach(System.out::println); // nullsFirst
System.out.println("nullsFirst : ");
personList.sort(Comparator.nullsFirst(Comparator.comparing(Persons::getName)));
personList.forEach(System.out::println);
}

Comparator接口和Comparable接口

这两个接口首先要做一个简单区别。

Comparable接口

* Lists (and arrays) of objects that implement this interface can be sorted
* automatically by {@link Collections#sort(List) Collections.sort} (and
* {@link Arrays#sort(Object[]) Arrays.sort}). Objects that implement this
* interface can be used as keys in a {@linkplain SortedMap sorted map} or as
* elements in a {@linkplain SortedSet sorted set}, without the need to
* specify a {@linkplain Comparator comparator}.<p>

可以看到注释中说明了实现了该接口的对象,在数组中可以使用Collections.sort或者Arrays.sort方法实现排序,或者实现了该接口的对象可以作为sortedMap或者SortedSet的key。这里也提到我们不用制定一个排序或者作为key的Comparator接口。

public interface Comparable<T> {
/**
* 省略部分注释
* <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
* -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This
* implies that <tt>x.compareTo(y)</tt> must throw an exception iff
* <tt>y.compareTo(x)</tt> throws an exception.)
*/
public int compareTo(T o);
}

compareTo方法上的注释中提到,必须确保 x.compareTo(y)y.compareTo(x)的结果是一致的,并且这也意味着当x.compartTo(y)抛出一个异常,那么y.compareTo(x)也应该去抛出一个异常,那么这里就思考到了一个关于null的设计:null.compareTo(obj)我们肯定知道会有NPE,那么你在实现compareTo方法的时候,如果obj.compareTo(null)这里也应该去抛出NPE。

这里就不去写具体的demo去演示了,这里理解为一个对象实现了Comparable接口,那么这个对象就是可比较的,并且在排序等场景下调用实现接口中的compareTo方法。

Comparator接口

Comparator接口要理解为比较器,实现其接口的类其实是比较器的一种实现,相当于一个比较的函数定义。来看下他的注释:

* A comparison function, which imposes a <i>total ordering</i> on some
* collection of objects. Comparators can be passed to a sort method (such
* as {@link Collections#sort(List,Comparator) Collections.sort} or {@link
* Arrays#sort(Object[],Comparator) 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 {@link SortedSet sorted sets} or {@link
* SortedMap sorted maps}), or to provide an ordering for collections of
* objects that don't have a {@link Comparable natural ordering}.<p>

这里我们看到Arrays、Collections也提供了重载的sort方法,支持传入一个集合/数组和Comparator接口的实例。当然当前列表/数组中的对象不一定是实现了Comparable接口。

类实现了comparable接口之后,可以直接调用排序方法;而当使用comparator时,不需要类实现,具体使用时(也就是调用某些方法时)的需要类和该comparator绑定起来来实现。comparable实现内部排序,Comparator是外部排序。

Comparator比较器的更多相关文章

  1. java.util下有一个Comparator(比较器)

    java.util下有一个Comparator(比较器) 它拥有compare(),用来比较两个方法. 要生成比较器,则用Sort中Sort(List,List(Compate)) 第二种方法更灵活, ...

  2. Comparable比较器和Comparator比较器

    1.Comparable比较器 在Arrays类中存在sort()排序方法,此方法可以直接对对象数组进行排序. public static void sort(Object[] a 根据元素的自然顺序 ...

  3. 2.3 comparator(比较器)

    1.comparator是java的一种机制,用来帮助我们给相同对象的不同属性排序 2.Comparable接口,是一个对象本身就已经支持自比较所需要实现的接口,如String,Integer自己就已 ...

  4. java中Comparator比较器顺序问题,源码分析

    提示: 分析过程是个人的一些理解,如有不对的地方,还请大家见谅,指出错误,共同学习. 源码分析过程中由于我写的注释比较啰嗦.比较多,导致文中源代码不清晰,还请一遍参照源代码,一遍参照本文进行阅读. 原 ...

  5. 菜鸡的Java笔记 comparator 比较器

    1.数组操作类: Arrays        2.两种比较器的使用: Comparable Comparator        3.实现二叉树算法            content (内容)   ...

  6. java:Comparator比较器

    /*Comparator是java.util包里的一个接口,使用时应该实现导入相应的包, *再写一个实现了Comparator接口的类,并复写int compare(Object o)方法, *写出你 ...

  7. Java Object类 instanceof关键字 练习:判断是否为同一人 集合按照人的年龄排序,如果年龄相同按名字的字母顺序升序 Comparator比较器

    package com.swift; public class Same_Person_Test { public static void main(String[] args) { /* * Obj ...

  8. java Comparator比较器排序法

    注意:排序的字段不为空,否则抛出空指针异常! 第一步:先编写一个比较器类 如下: 第二步:此集合的对象 EO 必须重写 此equals 方法 如图: 第三步:调用使用此比较器 如图:

  9. Java之ArrayList自定义排序,通过实现comparator比较器接口

    两种排序方式: 1.实体类实现Comparable接口,重写compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用Collections.sort()来排序对象数组 2.在调用方法的 ...

随机推荐

  1. Linux系列:快捷键、目录结构、用户目录

    一.快捷键 1.历史命令 查看历史命令:history [root@centos-master ~]# history 1 2020-10-25 21:03:39 2 2020-09-17 20:43 ...

  2. java 内存可见性

    java线程 -> 线程工作内存 -> 主物理内存 线程工作内存的原理是栈内是连续的小空间,寻址速度比堆快得多,将变量拷贝到栈内生成副本再操作 什么是重排序 代码指令可能并不是严格按照代码 ...

  3. Google Cayley图数据库使用方法

    最近在用Golang做流程引擎,对于流程图的存储,我看到了Google的Cayley图数据库,感觉它可能会比较适合我的应用,于是便拿来用了用. 项目地址在这里:https://github.com/g ...

  4. 2. HttpRunnner录制生成用例

    录制生成用例 为了简化测试用例的编写工作,HttpRunner 实现了测试用例生成的功能,对应的转换工具为一个独立的项目:har2case. 简单来说,就是当前主流的抓包工具和浏览器都支持将抓取得到的 ...

  5. Luogu P3200 [HNOI2009]有趣的数列

    题意 给定 \(n\),求有多少个长度为 \(2n\) 的排列 \(p\) 满足 对于 \(1\leq i\leq n\),\(p_{2i-1}<p_{2i}\). \(p_1<p_3&l ...

  6. 推荐给 Java 程序员的 7 本书

    < Java 编程思想> 适合各个阶段 Java 程序员的必备读物.书中对 Java 进行了详尽的介绍,与其它语言做了对比,解释了 Java 很多特性出现的原因和解决的问题.初学者可以通过 ...

  7. Windows 端口被占用,但进程号对应的进程不存在,使用Get-Process来查找进程挺方便的

    Windows上很少安装数据库,这次遇到一个小问题:数据库启动之后提示: 警告: 无法为 "*" 创建监听套接字 致命错误: 无法创建TCP/IP套接字 日志: 数据库系统已关闭 ...

  8. 【USACO】Strolling Cows

    Strolling Cows 给定有 \(n\) 个点 \(n\) 条边的有向图,每个点的出度都为 \(1\),求图中的最大环. 显然入度为 \(0\) 的点不可能为最大环上的点,所以考虑删点. 然后 ...

  9. 关于Java中泛型、反射和注解的扫盲篇

    泛型 泛型概念   泛型是在JDK1.5之后引入的,旨在让我们写出更加通用化,更加灵活的代码.通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类 ...

  10. 如何制作一本《现代Javascript教程》EPUB电子书

    制作一本<现代Javascript教程>电子书学习使用 计划学习JavaScript的同学可以看过来,今天就推荐个学习JavaScript的免费教程. 教程文档来源于 https://zh ...