| This class allows the ORDER BY clause of a JoSQL SQL clause to be used
as a Comparator. It should be noted that is the same as performing:
Query.execute(List) but there are times when having a separate comparator is desirable.
The EXECUTE ON ALL clause is supported but you must call:
JoSQLComparator.doExecuteOn(List) first to ensure that they are executed.
This class is basically just a thin wrapper around using the comparator gained by
calling:
Query.getOrderByComparator .
A note on performance, for small numbers of objects (around 1000) this comparator
has (for vanilla accessors, no function calls) pretty comparable performance against a
hand-coded Java Comparator that performs the same function. However start to scale the
numbers of objects and performance degrades, in testing for ~34000 FileWrapper objects
to order by: path DESC, lastModified, name, length took around: 1300ms.
The hand-coded Java Comparator took around: 180ms! The upshot is, if you need flexibility
and do not need to order large numbers of objects then use this kind of Comparator, if
performance and numbers of objects is an issue then hand-rolling your own Comparator
is probably best. As a side-note, to perform the following order by:
lower(path) DESC, lastModified, name, length using a JoSQLComparator took:
about: 1400ms. However modifying the hand-coded Comparator to use:
String.compareToIgnoreCase(String) then took about 860ms! And if you using:
String.toLowerCase for each string instead, it then takes about: 1800ms!
(Meaning that in certain circumstances JoSQL can be faster!)
Caching
It is not uncommon for a Comparator (even using the effecient merge-sort implementation of
java.util.Collections.sort(ListComparator) ) to perform thousands (even millions!)
of comparisons.
However since JoSQL does not automatically cache the results of calls to functions and
results of accessor accesses the performance of this kind of "dynamic" Comparator can
quickly degrade. To mitigate this it is possible to turn "caching" on whereby the
Comparator will "remember" the results of the functions on a per object basis and use those
values instead of calling them again. This is not without it's downside however.
Firstly since a reference to the object will be held it is important (if caching is used
that you call:
JoSQLComparator.clearCache() once the Comparator has been used to free up those
references (it was considered using a
java.util.WeakHashMap but that doesn't provide
exactly what's needed here).
It is recommended that caching is turned on when the Comparator is to be used in a sort
operation , i.e. calling:
java.util.Collections.sort(ListComparator) or similar
(however careful consideration needs to be given to the amount of memory that this
may consume, i.e. 4 bytes = 1 object reference, plus 1 List, plus 4 bytes per order
by "column" it soon adds up)
If the comparator is to be used in a
java.util.TreeMap or
java.util.TreeSet
then caching should not be used since the values may (and perhaps should) change over time
but due to caching the order won't change.
|