In Java, we can implement whatever sorting algorithm we want with any type. Using the Comparable interface and compareTo() method, we can sort using alphabetical order, String length, reverse alphabetical order, or numbers. The Comparator interface allows us to do the same but in a more flexible way.
There are a couple of awkward things with your example class:
price
and info
(more something for objects, not people);Anyway, here's a demo of how to use a 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);
}
}
And an equivalent Java 8 demo would look like this:
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);
}
}
Here's a super short template to do the sorting right away :
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)
}
});
if it's hard to remember, try to just remember that it's similar (in terms of the sign of the number) to:
lhs-rhs
That's in case you want to sort in ascending order : from smallest number to largest number.
Use People implements Comparable<People>
instead; this defines the natural ordering for People
.
A Comparator<People>
can also be defined in addition, but People implements Comparator<People>
is not the right way of doing things.
The two overloads for Collections.sort
are different:
<T extends Comparable<? super T>> void sort(List<T> list)
Comparable
objects using their natural ordering<T> void sort(List<T> list, Comparator<? super T> c)
Comparator
You're confusing the two by trying to sort a Comparator
(which is again why it doesn't make sense that Person implements Comparator<Person>
). Again, to use Collections.sort
, you need one of these to be true:
Comparable
(use the 1-arg sort
)Comparator
for the type must be provided (use the 2-args sort
)Also, do not use raw types in new code. Raw types are unsafe, and it's provided only for compatibility.
That is, instead of this:
ArrayList peps = new ArrayList(); // BAD!!! No generic safety!
you should've used the typesafe generic declaration like this:
List<People> peps = new ArrayList<People>(); // GOOD!!!
You will then find that your code doesn't even compile!! That would be a good thing, because there IS something wrong with the code (Person
does not implements Comparable<Person>
), but because you used raw type, the compiler didn't check for this, and instead you get a ClassCastException
at run-time!!!
This should convince you to always use typesafe generic types in new code. Always.
For the sake of completeness, here's a simple one-liner compare
method:
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person lhs, Person rhs) {
return Integer.signum(lhs.getId() - rhs.getId());
}
});
Java 8 added a new way of making Comparators that reduces the amount of code you have to write, Comparator.comparing. Also check out Comparator.reversed
Here's a sample
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class ComparatorTest {
@Test
public void test() {
List<Person> peopleList = new ArrayList<>();
peopleList.add(new Person("A", 1000));
peopleList.add(new Person("B", 1));
peopleList.add(new Person("C", 50));
peopleList.add(new Person("Z", 500));
//sort by name, ascending
peopleList.sort(Comparator.comparing(Person::getName));
assertTrue(peopleList.get(0).getName().equals("A"));
assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("Z"));
//sort by name, descending
peopleList.sort(Comparator.comparing(Person::getName).reversed());
assertTrue(peopleList.get(0).getName().equals("Z"));
assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("A"));
//sort by age, ascending
peopleList.sort(Comparator.comparing(Person::getAge));
assertTrue(peopleList.get(0).getAge() == 1);
assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1000);
//sort by age, descending
peopleList.sort(Comparator.comparing(Person::getAge).reversed());
assertTrue(peopleList.get(0).getAge() == 1000);
assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1);
}
class Person {
String name;
int age;
Person(String n, int a) {
name = n;
age = a;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
}
For the sake of completeness.
Using Java8
people.sort(Comparator.comparingInt(People::getId));
if you want in descending order
people.sort(Comparator.comparingInt(People::getId).reversed());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With