tags:

views:

3202

answers:

8

Assume you have some objects which have several fields they can be compared by:

public class Person {

    private String firstName;
    private String lastName;
    private String age;

    /* Constructors */

    /* Methods */

}

So in this example, when you ask if:

a.compareTo(b) > 0

you might be asking if a's last name comes before b's, or if a is older than b, etc...

What is the cleanest way to enable multiple comparison between these kinds of objects without adding unnecessary clutter or overhead?

  • java.lang.Comparable interface allows comparison by one field only
  • Adding numerous compare methods (i.e. compareByFirstName(), compareByAge(), etc...) is cluttered in my opinion.

So what is the best way to go about this?

+1  A: 

I think it'd be more confusing if your comparison algorithm were "clever". I'd go with the numerous comparison methods you suggested.

The only exception for me would be equality. For unit testing, it's been useful to me to override the .Equals (in .net) in order to determine if several fields are equal between two objects (and not that the references are equal).

Michael Haren
+4  A: 

Instead of comparison methods you may want to just define several types of "Comparator" subclasses inside the Person class. That way you can pass them into standard Collections sorting methods.

Marc Novakowski
+1  A: 

If there are multiple ways a user might order person, you could also have multiple Comparators setup as constants somewhere. Most of the sort operations and sorted collections take a comparator as a parameter.

sblundy
+12  A: 

You can write a comparator class which compares two Person objects, and you can examine as many of the fields as you like. You can put in a variable in your comparator that tells it which field to compare to, although it would probably be simpler to just write multiple comparators.

Elie
Exactly right. +1.
Dan Vinton
A: 

If you implement the Comparable interface, you'll want to choose one simple property to order by. This is known as natural ordering. Think of it as the default. It's always used when no specific comparator is supplied. Usually this is name, but your use case may call for something different. You are free to use any number of other Comparators you can supply to various collections APIs to override the natural ordering.

Also note that typically if a.compareTo(b) == 0, then a.equals(b) == true. It's ok if not but there are side effects to be aware of. See the excellent javadocs on the Comparable interface and you'll find lots of great information on this.

Mark Renouf
+1  A: 

You should implement Compareable<Person>. Assuming all fields will not be null (for simplicity sake), that age is an int, and compare ranking is last, first, age, the compareTo method is quite simple:

public int compareTo(Person p1, Person p2)
{
    int i = p1.firstName.compareTo(p2.firstName);
    if (i != 0) return i;

    i = p2.lastName.compareTo(p2.lastName);
    if (i != 0) return i;

    return p1.age - p2.age;
}
Steve Kuo
+1  A: 

You can also have a look at Enum that implements Comparator.

http://tobega.blogspot.com/2008/05/beautiful-enums.html

e.g. Collections.sort(myChildren, Child.Order.ByAge.descending());

Boune
This method looks really nice.
Bent André Solheim
A: 

My question builds on this and I'm not if Steve Kuo answered it. I've seen where you sort by one column or value like id, first name, last name, etc. But, what if I wanted to sort by last name, then first name? How would this be done?

Patrick