Java coding to compare and sort objects
Q. Can you write a simple program that compares two objects to return if they are equal or not? This method will be handy in defining your own equals( ) method.
A. This is usefull in domain or value object class to compare different object fields in an equals method
public class DomainObject { //protected because only inheriting domain classes can use it protected boolean isPropertyEqual(Object compare1, Object compare2) { // go here if compare1 is null, i.e. test cases 1 & 3 if (compare1 == null) { if (compare2 != null) { return false; } //go here if compare1 is not null, i.e. test cases 2 & 5 } else if (!compare1.equals(compare2)) { return false; } return true; //test cases 1 & 4 } public static void main(String[] args) { DomainObject d = new DomainObject(); Print(d.isPropertyEqual(null, null)); //test case 1 Print(d.isPropertyEqual("abc", null)); //test case 2 Print(d.isPropertyEqual(null, "abc")); //test case 3 Print(d.isPropertyEqual("abc", "abc"));//test case 4 Print(d.isPropertyEqual("abc", "cba"));//test case 5 } public static void Print(boolean bol){ System.out.println(bol); } }
Note: The above class must be abstract. It was not tagged abstract to demo via the main() method by creating a new DomainObject(). The above method can be used in an extending class like
public class Security extends DomainObject implements Serializable { private String id; //skipping other methods like getter/setter, toString, etc public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Security)) { return false; } //calling super class handy method we just created return isPropertyEqual(this.id, ((Security) obj).getId()); } public int hashCode() { return id.hashCode(); } }
Q. Can you write code to sort the following string values naturally (i.e. in alphabetical order)?
JEE, Java, Servlets, JMS, JNDI, JDBC, JSP, and EJB.
A. Here is the sample code that makes use of the default compareTo( ) provided in the String class as it implements the Comparable interface and the Collections utility class that provides a sorting method, which internally uses the efficient "merge sort" algorithm.
import java.util.Arrays; import java.util.Collections; import java.util.List; public class Sort1 { public static void main(String[] args) { List<string> values = Arrays.asList("JEE", "Java", "Servlets", "JMS", "JNDI", "JDBC", "JSP", "EJB"); Collections.sort(values); // uses the default compareTo(String anotherString) in the String class System.out.println(values); } }
Output:
[EJB, JDBC, JEE, JMS, JNDI, JSP, Java, Servlets]Q. Is there anything wrong with the above code?
A. Yes, 2 things -- firstly, the above sort is case sensitive, that is the uppercase takes priority over lowercase pushing 'Java' after 'JSP'. Secondly, if the collection had any null values, it will throw a NullpointerException.
These two issues can be rectified by providing a custom sorting implementation that ignores case and handles null values by pushing them to the end. The Collections class's sort method takes a Comparator implementation as a second argument. In the code below, the Comparator has been implemented as an anonymous inner class. The compare(...) method will be called a number of times by the Collections.sort(list, comparator).
import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class Sort2 { public static void main(String[] args) { List<String> values = Arrays.asList("JEE", "Java", null, "Servlets", null, "JMS", "JNDI", "JDBC", "JSP", null,"EJB"); //The comparator is defined as an anonymous inner class, but it can be //defined in its own class. Handles nulls and ignores case Collections.sort(values, new Comparator<String>() { @Override public int compare(String o1, String o2) { //push the null values to the end if(o1 == null){ if(o2 == null) { return 0; } return 1; } else if(o2 == null){ return -1; } return o1.compareToIgnoreCase(o2); } }); // anonymous inner class end System.out.println(values); } }
Q. Now, what if you have your own custom class like a Dog, Cat, etc instead of a library class like String, Integer, etc?
A. Here is an example of a JavaTechnology custom object that implements a default sorting logic based on the rank (i.e popularity).
public class JavaTechnology implements Comparable<JavaTechnology>{ private String name; private int rank; // popularity lower value means more popular public JavaTechnology(String name, int rank){ this.name = name; this.rank = rank; } //default implementation by rank alone @Override public int compareTo(JavaTechnology technology) { int rank1 = this.rank; int rank2 = technology.rank; if (rank1 > rank2){ return +1; }else if (rank1 < rank2){ return -1; }else{ return 0; } } //required for printing, displaying, etc. @Override public String toString() { return "(" + name + " , " + rank + ")"; } }
Now, a simple test class
import java.util.Arrays; import java.util.Collections; import java.util.List; public class Sort3Test { public static void main(String[] args) { JavaTechnology jt1 = new JavaTechnology("JEE", 1); JavaTechnology jt2 = new JavaTechnology("Java", 1); JavaTechnology jt3 = new JavaTechnology("Servlets", 2); JavaTechnology jt4 = new JavaTechnology("JSP", 2); JavaTechnology jt5 = new JavaTechnology("JNDI", 3); JavaTechnology jt6 = new JavaTechnology("EJB", 4); JavaTechnology jt7 = new JavaTechnology("JMS", 5); List<javatechnology> values = Arrays.asList(jt1, jt2, jt3, jt4, jt5, jt6, jt7); Collections.sort(values); // invokes the compareTo(...) method in JavaTechnology a number of times System.out.println(values); } }
Output:
[(JEE , 1), (Java , 1), (Servlets , 2), (JSP , 2), (JNDI , 3), (EJB , 4), (JMS , 5)]
Q. What if you have a specific scenario where you want to first sort by rank and then alphabetically if the ranks are same?
A. Any number of Comparator classes can be created to sort them differently as shown below.
import java.util.Comparator; public class JavaTechnologyComparator implements Comparator<JavaTechnology> { @Override public int compare(JavaTechnology t1, JavaTechnology t2) { //handle null values here Integer rank1 = t1.getRank(); Integer rank2 = t2.getRank(); int rankVal = rank1.compareTo(rank2); int nameVal = t1.getName().toLowerCase().compareTo(t2.getName().toLowerCase()); //if same rank, then sort by name if(rankVal == 0){ return nameVal; } //else sort by rank return rankVal ; } }
Now, the Sort3Test class has been slightly modified to use a Comparator .
import java.util.Collections; import java.util.List; public class Sort3Test { public static void main(String[] args) { JavaTechnology jt1 = new JavaTechnology("JEE", 1); JavaTechnology jt2 = new JavaTechnology("Java", 1); JavaTechnology jt3 = new JavaTechnology("Servlets", 2); JavaTechnology jt4 = new JavaTechnology("JSP", 2); JavaTechnology jt5 = new JavaTechnology("JNDI", 3); JavaTechnology jt6 = new JavaTechnology("EJB", 4); JavaTechnology jt7 = new JavaTechnology("JMS", 5); List<JavaTechnology> values = Arrays.asList(jt1, jt2, jt3, jt4, jt5, jt6, jt7); Collections.sort(values, new JavaTechnologyComparator()); // invokes the compare(...) in JavaTechnologyComparator // a number of times System.out.println(values); } }
The output will be:
[(Java , 1), (JEE , 1), (JSP , 2), (Servlets , 2), (JNDI , 3), (EJB , 4), (JMS , 5)]This should now enable you to sort any Java objects.
-->
2 Comments:
nice article, useful!
If we start listing down the scenario where we can use the compareTo method for adding sorting behavior. The list is going to grow like anything. But one place where compareTo or Comparable interface isn't much useful is when compairing objects from third party classes.
Post a Comment
Subscribe to Post Comments [Atom]
<< Home