This code is used to sort a List. The list could contain in the thousands of elements but less than 10k.
protected <E> int compareFields(E o1, E o2, String fieldName){
try {
Comparable o1Data = (Comparable) o1.getClass().getMethod(fieldName).invoke(o1);
Comparable o2Data = (Comparable) o2.getClass().getMethod(fieldName).invoke(o2);
return o1Data == null ? o2Data == null ? 0 : 1 :
o2Data == null ? -1 : o1Data.compareTo(o2Data);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
I was advised to
"Please don't use reflection for things like this!! Either supply the method with a suitable Comparator, or a method to extract the relevant property (may be computed in a way not supported by the original type), or both."
An example of a better way to do this would be nice.
Context: I've got many screens with data tables. Each one is build from a List. Each data table needs to be sortable by each of its 6 columns. The columns are either Date or String.
Using reflection here will potentially be much slower, as you are adding number of stack frames to each comparison by using getClass
, getMethod
and invoke
rather than using the objects' native compare method.
Ideally, you would write the method to avoid the use of object
in the signature. A "suitable Comparator" would at least be strongly bound to the objects' type (which you assume are the same). If you must have dynamic field comparison (as it appears), then at least the reflection could be encapsulated in that comparator.
If you are going to call this thousands of times, though, it would be best to pre-bind a Comparator to the field you are sorting by. This way, you only call getMethod
once up front, rather than once for each individual comparison.
It's hard to give a good example without context, so for now here's a small list of why it's not the best idea:
The other answers described well why it is not advised to use reflection. I want to add an example using a more conventional solution.
Instead of specifying the field that is used to compare the two objects, you should take a Comparator
instance as an argument. This way the client who uses this method can specify how to compare the two objects.
protected <E> int compareFields(E o1, E o2, Comparator<E> comparator) {
return comparator.compare(o1, o2);
}
And an example call to this function would look like this:
MyClass a = ...;
MyClass b = ...;
Comparator<MyClass> intFieldComparator = new Comparator<MyClass> {
public int compare(MyClass o1, MyClass o2) {
int field1 = o1.getIntField();
int field2 = o2.getIntField();
return field2 - field1;
}
};
compareFields(a, b, intFieldComparator);
You can define different comparators if you want to compare the objects using several fields.
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