Videos
There are a couple of awkward things with your example class:
- it's called People while it has a
priceandinfo(more something for objects, not people); - when naming a class as a plural of something, it suggests it is an abstraction of more than one thing.
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);
}
}
EDIT
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.
EDIT: First of all, a couple of things:
- The
@Overrideannotation should not be mandatory. If Eclipse wants you to put it on, don't worry. - Don't write your own Comparator interface. Delete that definition NAO and use the one provided by Java. Reinventing the wheel probably violates the Unspoken Code of Computer Programming in about 15 different ways. Use
import java.util.Comparator;at the very top of your code (before thepublic classstuff) to a) use the version given by Java and b) make your code compatible with pretty much everything else that exists in the world.
The Comparator interface is not used to create a class that can put itself in order. This is the Comparable interface.
Both are similar, so I will describe both here.
java.util.Comparator
The Comparator interface, as you already know, has one method: compare. Comparator is generic (uses the angle brackets <>) and takes the type it will compare inside the <>. The thing is that Comparators are used to compare items of other classes. For example, I could create a Comparator for java.lang.Integers that returns the opposite of the "natural order" (how Integers are usually ordered).
Comparators are used mostly to give other objects a way to sort their parameters when they are not in natural order. For example, the java.util.TreeSet class takes a Comparator for its sorting capability.
java.lang.Comparable
Comparable's purpose is to say that an object can be compared. It is also generic and takes the type that it can be compared to. For example, a Comparable<String> can be compared to Strings.
Comparable has one method: compareTo(). Unlike Comparator's compare(), compareTo takes one parameter. It works like compare, except it uses the invoking object as one parameter. So, comparableA.compareTo(comparableB) is the same as comparator.compare(comparableA, comparableB).
Comparable mostly establishes the natural order for objects, and is the default way to compare objects. Comparator's role is to override this natural order when one has different needs for data comparison or sorting.
ArrayList Sorting
To sort a List, you could use the method already available: scroll down to sort on the java.util.Collections class. One method takes a Comparator, the other does not. sort is static; use Collections.sort(...), not Collections c = new Collections(); c.sort(...). (Collections doesn't even have a constructor anyway, so meh.)
To use the Comparator interface you have to implement it and pass it as an anonymous class to Collections.sort(List list, Comparator c) as the second parameter.
If you want to pass only the list to Collections.sort(List list) then your Item class has to the implement Comparable interface.
So in both cases the Collections.sort methods know how to order the elements in your list
here is some sample code:
Item class implementing Comparable + Inventory holding a list of items
Copypublic class Item implements Comparable<Item> {
String id = null;
public Item(String id) {
this.id = id;
}
@Override
public String toString() {
return id;
}
@Override
public int compareTo(Item o) {
return - id.compareToIgnoreCase(o.id);
}
}
public class Inventory {
List<Item> items = new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public static void main(String[] args) {
Inventory inventory = new Inventory();
inventory.addItem(new Item("2"));
inventory.addItem(new Item("4"));
inventory.addItem(new Item("1"));
inventory.addItem(new Item("7"));
Collections.sort(inventory.items, new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
return o1.id.compareToIgnoreCase(o2.id);
}
});
System.out.println(inventory.items);
Collections.sort(inventory.items);
System.out.println(inventory.items);
}
}
Output
Copy[1, 2, 4, 7] // ascending
[7, 4, 2, 1] // descending since the compareTo method inverts the sign of the comparison result.