Tutorial :Java, how to add a “comparator” class to increase code reusability



Question:

Preface: I'm posting this on behalf of a friend (who's apparently to shy to post it himself), I browsed through the related questions and I didn't seem to find any duplicate.. But do note that I don't know Java at all so I apologize in advance if this is a duplicate!

This is part of the code:

public class ElencoEsami implements Comparable{      private ArrayList<EsameMedico>  a = new ArrayList<EsameMedico>();      private Comparable comparatore;      public ElencoEsami() {      }      public void addEsame(EsameMedico e) {          if (a.isEmpty()) {              a.add(0,e);              return;          }            for(int i=0;i<a.size();i++) {              if (a.get(i).getData().after(e.getData())) {                  a.add(i,e);                  break;              }          }          a.add(e);      }      public int compareTo(Object o) {  // ?????      }    }  

My friend wants to implement "addEsame" so that it maximizes code reusability, in particular he wants to be able to change the way the list is ordered (right now it's ordered by name) simply by adding a new class (a comparator class I believe? Or at least that's how I would do it in C++).

Thank you!


Solution:1

First of all, use Collections.sort(List list, Comparator c)

And then, code as many Comparator as you need sorting orders

That's it.


Solution:2

Typically, if you want to be able to reorder a list using a comparator, you don't need to implement Comparable (only good for one ordering), you create new Comparator objects which can be written outside that class and can specify any ordering possible (by the getters in that class)

All you need is a setter for the Comparator (a field in that class) which resorts your list after changing.

From another class it would look like:

your_object.setComparator(new Comparator<ElencoEsami>() {      public int compare(ElencoEsami o1, ElencoEsami o2) {          // do some comparing...      }  });  

In your class it would look like:

public void setComparator(Comparator<? extends ElencoEsami> comp) {      this.comparator = comp;      Collections.sort(this.listOfItems, comp);  }  


Solution:3

If I want to implement a number of comparators in a reusable way, I like to implement them as enums (based on ideas from Old Tech Per):

public class EsameMedico {      ...        /** Enumeration of {@link Comparator}s for {@code EsameMedico}. */      public static enum Comparators implements Comparator<EsameMedico> {          /** Compares by name. */          BY_NAME {              public int compare(final EsameMedico em1, final EsameMedico em2) {                  return em1.name.compareTo(em2.name);              }                public void sort(final List<EsameMedico> l) {                  Collections.sort(l, BY_NAME);              }          },          /* Compares by whatever. */          BY_WHATEVER {              public int compare(final EsameMedico em1, final EsameMedico em2) {                  return /* compare by "whatever" */;              }                public void sort(final List<EsameMedico> l) {                  Collections.sort(l, BY_WHATEVER);              }          };            /** Sorts the list by this criterion. */          public abstract void sort(List<EsameMedico> l);      }        ...  }  

Note though, that with lists you have to maintain the order of the list yourself on inserts. If you want to keep your collections sorted automagically, SortedSet may be helpful. TreeSet, an implementation of the SortedSet interface, takes a Comparator in its constructor and sorts its elements itself.


Solution:4

Sun has a page in the Java interfaces trail about Object Ordering. It gives a brief overview of Comparators and how to write them.


Solution:5

If you want to have your objects sorted while you add them with addEsame, without calling Collections.sort(), use a TreeMap with a key you want to sort by. If your objects are distinct, use a TreeSet.

And another thing:

declare your list like this:

private List<EsameMedico> a;  

(Or Map, Set, whatever you choose)

And initialize it in the constructor:

a = new ArrayList<EsameMedico>();  

(Or TreeMap ...)

Because if you would extend the class ElencoEsami you would have some strange results.


Solution:6

If you want to change the ordering of the list you can use the Collections.sort() method that takes a comparator as an argument.

Based on your code you seem to have some confusion between the Comparable and Comparator interfaces. A class that implements the Comparable interface means that it has some sort of natural ordering (e.g. the Integer class is naturally ordered based on the int it represents). Using a comparator you can order objects based on some other ordering criteria.

From the code you have posted, I would like to ask whether you actually intend to order the ElencoEsami class or if you were intending to order the EsameMedico objects?

If its the EsameMedio class that should be ordered, then its the EsameMedico class that should implement the Comparable interface. Assuming that the comparison you do in the addEsame() method is the natural ordering of the EsameMedico class, you can implement the compareTo() method in EsameMedico like this:

public class EsameMedico implements Comparable<EsameMedico>{    ...    public int compareTo(Object o) {      EsameMedico e = (EsameMedico)o;      if(getData().after(e.getData())) {          return 1;      } else if(e.getData().after(getData())){          return -1;      } else {          return 0;      }  }  

}

You can then change your addEsame() method to simply insert into the list and call Collections.sort() after each insertion. A better approach of course, would be to use a TreeSet rather than an ArrayList. If you did this each EsameMedico would be inserted according to its natural order and you wouldn't have to perform any sorting yourself.


Solution:7

  1. Use the sort method instead of "sorting by hand";
  2. As pointed by twolfe18, use Comparator objects, and take a close look inside the Strategy design pattern.


Solution:8

I found this example immensely useful: http://www.javabeat.net/tips/20-sorting-custom-types-in-java.html

The key for me was an example of a Comparator class like so:

package tips.sort;    import java.util.Comparator;    public class MovieComparator implements Comparator<Movie>{    @Override  public int compare(Movie movie1, Movie movie2) {        int rank1 = movie1.getRank();      int rank2 = movie2.getRank();        if (rank1 > rank2){          return +1;      }else if (rank1 < rank2){          return -1;      }else{          return 0;      }  }  

}


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »