0

Please could someone suggest the best possible solution to the following problem (this is part of a program I am trying to code) :

I have a class Foo with member variables and another class Bar which extends Foo. Bar adds extra member variables. Bar objects are stored in a collection and as such I would like to order these objects by any of their member variables.

I considered using an enum type containing the member variables for the classes that could be passed as an argument to the compareTo() method but as enumerated types are implicitly static I cannot add parameters for the member variables for Bar or any other classes that may extend Foo that I want to compare. For example, I want to compare two Bar classes by the member variable 'myVar' I would call something like bar1.compareTo(bar2, MyEnum.MYVAR) and the classes would be compared against their myVar values. I am thinking that I may just have to create seperate methods to order by each member variable but want to use compareTo() as it is used by Java collections to automatically sort its items (I believe).

That is as clearly as I can describe the problem but I am probably going about achieving this the completely wrong way. Any pointers would be greatly appreciated.

EDIT - This is similar behaviour to sorting columns in a Windows Explorer window by different attributes i.e. Date Modified, File Name, size, etc.

  • 1
    Ummmm....`compareTo` only takes one argument. Why not just override `compareTo` in `Bar`? –  Dec 07 '12 at 20:13
  • I am already overriding compareTo in Bar, my problem is sorting a collection of Bar by a specified member variable. – user1886491 Dec 07 '12 at 20:23
  • I guess some code snippets may improve the readability and the clarity of the question. Anyway, that's a good start, being your first question. – Giulio Muscarello Dec 07 '12 at 20:34
  • `compareTo` doesn't sort. `compareTo` compares. Use `sort` to sort. –  Dec 08 '12 at 01:13

2 Answers2

4

You're better off using a Comparator instead to encapsulate this particular comparation logic. You can do as many Comparator object as possible comparations you want to make or, as suggested, have the Comparator to compare based on a determined field.

It's up to you if you want to have multiple comparators or just one, but if you want to make complex comparations based on multiple fields I suggest you create a particular comparator for that.

Fritz
  • 9,987
  • 4
  • 30
  • 49
  • 3
    You could also create a Comparator that takes an argument in its constructor that specifies which field to use in comparison. That way you only need one Comparator and it can be used to sort by different fields. – jahroy Dec 07 '12 at 20:23
  • @jahroy As long as it implements the `Comparator` interface, no harm is done. The only thing is that you have to check which field you'll use, making the code a little more complex. There's also the case when a comparation is not that trivial, or when there is a comparation based on multiple fields. Anyway, it is a good point. – Fritz Dec 07 '12 at 20:27
  • It would work pretty well if each possible sort field implements comparable. Obviously there are cases where it wouldn't be trivial to implement. Here's an answer that provides an example: http://stackoverflow.com/a/4136060/778118 – jahroy Dec 07 '12 at 20:29
  • I know what you mean. I'm not against the idea of a comparator for simple fields, but IMO having particular extra comparators for other complex comparations would make the code much more cleaner. – Fritz Dec 07 '12 at 20:37
  • Yep. Not arguing that point at all. Multiple comparators is a good solution. That being said, here's one more link that shows an example of a dynamic comparator: http://stackoverflow.com/a/13577772/778118 – jahroy Dec 07 '12 at 20:39
  • @jahroy that final link you posted is just what I was looking for, will go and implement it now. Is there a thanks button on stackoverflow? newbie – user1886491 Dec 07 '12 at 20:53
  • There is no _thanks button_, but you can upvote answers and comments that you find helpful. You should upvote this answer and the one in my link (if you choose to and are able). – jahroy Dec 07 '12 at 21:33
1

It is very tricky to implement a compareTo using inheritance. You better don't do that. Use aggregation, and you are out of problems:

class Bar {
  Foo foo;
  String barName;
  public getName() { return barName; }
}

Further if you need different comparator methods (e.g ascending descending, by attribute) then define a Comparator : (unfort. I have Eclipse not open, please correct if syntax fails)

public class BarComparator implements Comparator<Bar> {

      @Override
      public int compare(Bar b1, Bar b2) {
        if (b1.getName() == null && b2.getName() == null) {
          return 0;
        }
        if (b1.getName() == null) {
          return 1;
        }
        if (b2.getName() == null) {
          return -1;
        }
        return b1.getName().compareTo(b2.getName());
      }
    }
AlexWien
  • 28,470
  • 6
  • 53
  • 83
  • Your example trys to assign a new _Comparable_ to a _Comparator_. That won't work (obviously). A Comparator has two methods: _compare_, and _equals_. – jahroy Dec 07 '12 at 20:37