Вопрос-ответ

How to use Comparator in Java to sort

Как использовать Comparator в Java для сортировки

Я научился использовать comparable, но у меня возникли трудности с Comparator. У меня ошибка в моем коде:

Exception in thread "main" java.lang.ClassCastException: New.People cannot be cast to java.lang.Comparable
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at New.TestPeople.main(TestPeople.java:18)

Вот мой код:

import java.util.Comparator;

public class People implements Comparator {
private int id;
private String info;
private double price;

public People(int newid, String newinfo, double newprice) {
setid(newid);
setinfo(newinfo);
setprice(newprice);
}

public int getid() {
return id;
}

public void setid(int id) {
this.id = id;
}

public String getinfo() {
return info;
}

public void setinfo(String info) {
this.info = info;
}

public double getprice() {
return price;
}

public void setprice(double price) {
this.price = price;
}

public int compare(Object obj1, Object obj2) {
Integer p1 = ((People) obj1).getid();
Integer p2 = ((People) obj2).getid();

if (p1 > p2) {
return 1;
} else if (p1 < p2){
return -1;
} else {
return 0;
}
}
}
import java.util.ArrayList;
import java.util.Collections;

public class TestPeople {
public static void main(String[] args) {
ArrayList peps = new ArrayList();

peps.add(new People(123, "M", 14.25));
peps.add(new People(234, "M", 6.21));
peps.add(new People(362, "F", 9.23));
peps.add(new People(111, "M", 65.99));
peps.add(new People(535, "F", 9.23));

Collections.sort(peps);

for (int i = 0; i < peps.size(); i++){
System.out.println(peps.get(i));
}
}
}

Я считаю, что это должно что-то делать с приведением в методе compare, но я поиграл с этим и все еще не мог найти решение

Переведено автоматически
Ответ 1

В вашем классе example есть пара неудобных моментов:


  • он называется People, хотя в нем есть price и info (скорее что-то для объектов, а не для людей);

  • когда имя класса является множественным числом чего-либо, это предполагает, что это абстракция более чем одной вещи.

В любом случае, вот демонстрация того, как использовать Comparator<T>:

public class ComparatorDemo {

public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Joe", 24),
new Person("Pete", 18),
new Person("Chris", 21)
);
Collections.sort(people, new LexicographicComparator());
System.out.println(people);
Collections.sort(people, new AgeComparator());
System.out.println(people);
}
}

class LexicographicComparator implements Comparator<Person> {
@Override
public int compare(Person a, Person b) {
return a.name.compareToIgnoreCase(b.name);
}
}

class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person a, Person b) {
return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
}
}

class Person {

String name;
int age;

Person(String n, int a) {
name = n;
age = a;
}

@Override
public String toString() {
return String.format("{name=%s, age=%d}", name, age);
}
}

Редактировать

И эквивалентная демонстрация Java 8 будет выглядеть следующим образом:

public class ComparatorDemo {

public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Joe", 24),
new Person("Pete", 18),
new Person("Chris", 21)
);
Collections.sort(people, (a, b) -> a.name.compareToIgnoreCase(b.name));
System.out.println(people);
Collections.sort(people, (a, b) -> a.age < b.age ? -1 : a.age == b.age ? 0 : 1);
System.out.println(people);
}
}
Ответ 2

Вот очень короткий шаблон для выполнения сортировки сразу :

Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(final Person lhs, Person rhs) {
// TODO return 1 if rhs should be before lhs
// return -1 if lhs should be before rhs
// return 0 otherwise (meaning the order stays the same)
}
});

Если это трудно запомнить, попробуйте просто запомнить, что это похоже (с точки зрения знака числа) на:

 lhs-rhs 

Это на случай, если вы хотите выполнить сортировку в порядке возрастания: от наименьшего числа к наибольшему.

Ответ 3

Используйте People implements Comparable<People> вместо этого; это определяет естественный порядок для People.

A Comparator<People> также может быть определен дополнительно, но People implements Comparator<People> это неправильный способ выполнения действий.

Две перегрузки для Collections.sort различны:


  • <T extends Comparable<? super T>> void sort(List<T> list)

    • Сортирует Comparable объекты, используя их естественный порядок


  • <T> void sort(List<T> list, Comparator<? super T> c)

    • Сортирует все, что угодно, используя совместимый Comparator


Вы путаете эти два параметра, пытаясь отсортировать Comparator (опять же, поэтому это не имеет смысла Person implements Comparator<Person>). Опять же, для использования Collections.sort вам нужно, чтобы одно из этих значений было истинным:


  • Тип должен быть Comparable (используйте 1 аргумент sort)

  • Должно быть указано Comparator для типа (используйте 2 аргумента sort)

Связанные вопросы


Кроме того, не используйте необработанные типы в новом коде. Необработанные типы небезопасны, и они предоставлены только для совместимости.

То есть вместо этого:

ArrayList peps = new ArrayList(); // BAD!!! No generic safety!

вам следовало использовать универсальное объявление typesafe, подобное этому:

List<People> peps = new ArrayList<People>(); // GOOD!!!

Затем вы обнаружите, что ваш код даже не компилируется !! Это было бы хорошо, потому что с кодом что-то не так (Person не делает implements Comparable<Person>), но поскольку вы использовали необработанный тип, компилятор не проверил это, и вместо этого вы получаете ClassCastException во время выполнения!!!

Это должно убедить вас всегда использовать типобезопасные универсальные типы в новом коде. Всегда.

Смотрите также

Ответ 4

Для полноты картины приведем простой однострочный compare метод:

Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person lhs, Person rhs) {
return Integer.signum(lhs.getId() - rhs.getId());
}
});
java