我读过关于使用比较器排序数组列表的内容,但在所有的例子中,人们都使用了compareTo,根据一些研究,它是字符串的一种方法。

我想根据自定义对象的一个属性(Date对象)对其数组列表进行排序 (getStartDay())。通常我通过item1.getStartDate().before(item2.getStartDate())比较它们,所以我想知道我是否可以写一些像这样的东西:

public class CustomComparator {
    public boolean compare(Object object1, Object object2) {
        return object1.getStartDate().before(object2.getStartDate());
    }
}

public class RandomName {
    ...
    Collections.sort(Database.arrayList, new CustomComparator);
    ...
}

当前回答

是的,这是可能的,例如在这个答案中,我根据类IndexValue的属性v进行排序

    // Sorting by property v using a custom comparator.
    Arrays.sort( array, new Comparator<IndexValue>(){
        public int compare( IndexValue a, IndexValue b ){
            return a.v - b.v;
        }
    });

如果您注意到这里,我正在创建一个匿名的内部类(这是用于闭包的Java),并将其直接传递给类Arrays的排序方法

您的对象也可以实现Comparable(这是String和Java中的大多数核心库所做的),但这将定义类本身的“自然排序顺序”,并且不允许您插入新的类。

其他回答

具有自然排序顺序的类(例如类Number)应该实现Comparable接口,而没有自然排序顺序的类(例如类Chair)应该提供Comparator(或匿名Comparator类)。

两个例子:

public class Number implements Comparable<Number> {
    private int value;

    public Number(int value) { this.value = value; }
    public int compareTo(Number anotherInstance) {
        return this.value - anotherInstance.value;
    }
}

public class Chair {
    private int weight;
    private int height;

    public Chair(int weight, int height) {
        this.weight = weight;
        this.height = height;
    }
    /* Omitting getters and setters */
}
class ChairWeightComparator implements Comparator<Chair> {
    public int compare(Chair chair1, Chair chair2) {
        return chair1.getWeight() - chair2.getWeight();
    }
}
class ChairHeightComparator implements Comparator<Chair> {
    public int compare(Chair chair1, Chair chair2) {
        return chair1.getHeight() - chair2.getHeight();
    }
}

用法:

List<Number> numbers = new ArrayList<Number>();
...
Collections.sort(numbers);

List<Chair> chairs = new ArrayList<Chair>();
// Sort by weight:
Collections.sort(chairs, new ChairWeightComparator());
// Sort by height:
Collections.sort(chairs, new ChairHeightComparator());

// You can also create anonymous comparators;
// Sort by color:
Collections.sort(chairs, new Comparator<Chair>() {
    public int compare(Chair chair1, Chair chair2) {
        ...
    }
});

是的,你可以。比较项有两个选项,Comparable接口和Comparator接口。

这两个接口都允许不同的行为。Comparable允许您使对象的行为与您刚刚描述的String类似(实际上,String实现了Comparable)。第二个,Comparator,允许你做你要求做的事情。你会这样做:

Collections.sort(myArrayList, new MyComparator());

这将导致收集。方法来使用比较器的排序机制。如果数组列表中的对象实现了可比性,你可以这样做:

Collections.sort(myArrayList);

Collections类包含许多这些有用的常用工具。

因为Date实现了Comparable,所以它有一个compareTo方法,就像String一样。

所以你的自定义比较器可以是这样的:

public class CustomComparator implements Comparator<MyObject> {
    @Override
    public int compare(MyObject o1, MyObject o2) {
        return o1.getStartDate().compareTo(o2.getStartDate());
    }
}

compare()方法必须返回一个int值,因此不能像计划的那样直接返回一个布尔值。

你的排序代码就像你写的那样:

Collections.sort(Database.arrayList, new CustomComparator());

如果你不需要重用你的比较器,一种稍短的方法是把它写成一个内联匿名类:

Collections.sort(Database.arrayList, new Comparator<MyObject>() {
    @Override
    public int compare(MyObject o1, MyObject o2) {
        return o1.getStartDate().compareTo(o2.getStartDate());
    }
});

因为java 8

现在你可以用比较器的lambda表达式来写最后一个例子:

Collections.sort(Database.arrayList, 
                        (o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));

List有一个sort(Comparator)方法,所以你可以进一步缩短:

Database.arrayList.sort((o1, o2) -> o1.getStartDate().compareTo(o2.getStartDate()));

这是一个非常常见的习惯用法,因此有一个内置方法可以为具有Comparable键的类生成Comparator:

Database.arrayList.sort(Comparator.comparing(MyObject::getStartDate));

所有这些都是等价的形式。

您可以在2016年德国斯图加特的Java论坛上看一看这个演讲。

只有少数幻灯片使用德语,99%的内容是“基于英语”的Java源代码;就像

someCollection.sort(
  OurCustomComparator
    .comparing(Person::getName)
    .thenComparing(Person::getId)
);

其中OurCustomComparator使用默认方法(和其他有趣的想法)。如图所示,导致非常简洁的代码,以选择一些getter方法进行排序;以及超级简单的排序标准链接(或反转)。

如果你对java8感兴趣,你可以在那里找到很多材料来开始学习。

好吧,如果你使用Java 8或更老的版本,这里是最好的解决方案。

Collections.sort(studentList, Comparator.comparing(Student::getCgpa).reversed().thenComparing(Student:: getFname).thenComparing(Student::getId));

在这种情况下,它将首先使用'getCgpa'进行排序,对于第二部分,它将使用getFname和getId进行排序。这是场进入pojo类。