When sorting a list, is there any performance difference between using a java Comparator in-line (with an anonymous inner class) vs implementing a separate custom Comparator class?
1.
public class SortByErrorComparator implements Comparator<WorkflowError> {
public int compare(WorkflowError obj1, WorkflowError obj2) {
return obj1.getErrorCode().compareTo(obj2.getErrorCode());
}
}
Collections.sort(list, new SortByErrorComparator()) ;
2.
Collections.sort(list, new Comparator<WorkflowError>() {
public int compare(WorkflowError obj1, WorkflowError obj2) {
return obj1.getErrorCode().compareTo(obj2.getErrorCode());
}
});
Also, when will the compare()
method be invoked?
Comparable in Java is an object to compare itself with another object, whereas Comparator is an object for comparing different objects of different classes. Comparable provides the compareTo() method to sort elements in Java, whereas Comparator provides compare() method to sort elements in Java.
1) Comparable provides a single sorting sequence. In other words, we can sort the collection on the basis of a single element such as id, name, and price. The Comparator provides multiple sorting sequences. In other words, we can sort the collection on the basis of multiple elements such as id, name, and price etc.
Comparator detaches the sorting logic from your object and contains the compareTo() logic within your sort() method.
The compare() method accepts two objects as input parameters and returns an integer value. int compare(T o1, T o2); Comparator decides the sorting order based on the integer value returned from the compare() method. 0, if values in o1 and o2 are equal.
There's also option 3 - a lambda Function
:
Collections.sort(list, (a, b) -> a.getErrorCode().compareTo(b.getErrorCode()));
which should be about 2 x faster, according to this benchmark data.
... or (thanks to @JB Nizet) option 4:
list.sort(Comparator.comparing(WorkflowError::getErrorCode))
I made a little test and found no difference (just in some small run the inline comparator shows a slightly better performace). This is the code used to make the test:
public class ComparatorTest {
private static final int MAX = 1000000;
private static final int RUN = 10000;
public static void main(String[] args) {
List<A> list = new ArrayList<A>();
long externalComparatorClassTotalTime = 0;
long inlineCompartorTotalTime = 0;
for (int i = RUN; i > 0; i--) {
init(list);
externalComparatorClassTotalTime += externalComparatorClassTest(list);
init(list);
inlineCompartorTotalTime += inlineCompartorTest(list);
}
System.out.format("List with %d elements and %d runs%n", MAX, RUN);
System.out.println("external Comparator class average millis: " + externalComparatorClassTotalTime / RUN);
System.out.println("inline Comparator class average millis: " + inlineCompartorTotalTime / RUN);
}
private static void init(List<A> list) {
list.clear();
for (int i = MAX; i > 0; i--) {
list.add(new A(i));
}
}
private static long inlineCompartorTest(List<A> secondList) {
long start = System.currentTimeMillis();
Collections.sort(secondList, new Comparator<A>() {
public int compare(A obj1, A obj2) {
return obj1.getVal().compareTo(obj2.getVal());
}
});
return System.currentTimeMillis() - start;
}
private static long externalComparatorClassTest(List<A> firstList) {
long start = System.currentTimeMillis();
Collections.sort(firstList, new MyComparatorOne());
return System.currentTimeMillis() - start;
}
}
Comparator class:
public class MyComparatorOne implements Comparator<A> {
public int compare(A obj1, A obj2) {
return obj1.getVal().compareTo(obj2.getVal());
}
}
and the output is:
List with 1000000 elements and 10000 runs
external Comparator class average millis: 3
inline Comparator class average millis: 3
If you have several invocation to the comparator keeping an instance of it would be helpful
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With