Reputation: 1724
I am trying to sort a list with its member attribute by using Comparator.comparing()
, and the attribute is selected by the user. Consider the case below:
public class MyClass extends BaseClass
{
private String attr1;
private Date attr2;
private ChildClass attr3;
//getter and setter
}
public class ChildClass extends BaseClass
{
private String attr1;
private Date attr2;
private int attr3;
//getter and setter
}
This is what I have tried, but having compile error.
private Map<String, Function<MyClass, ?>> sortingOptions = new HashMap<>();
private String sortBy; //sorting attribute selected by user
@PostConstruct
public void init()
{
//my list to be sort
List<MyClass> list = myService.getList();
sortingOptions.put("attr1", MyClass::getAttr1);
sortingOptions.put("attr2", MyClass::getAttr2);
//......
}
//listener for sorting option changed
public void sortOptionChangedListener()
{
//this line of code having error
list.sort(Comparator.comparing(sortingOptions.get[sortBy]));
}
The error showing is
The method comparing(Function<? super T,? extends U>) in the type Comparator is not applicable for the arguments (Function<MyClass,capture#3-of ?>)
Upvotes: 3
Views: 2612
Reputation: 23
I don't think Clinton's right. The following is the Comparator::comparing source code.
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
Its parameters is a function whose input parameter is T and the return value is Comparable, this does not apply to a simple getter. I think reflection can do this, but more complex.
Upvotes: 0
Reputation: 8363
You can do this:
private Map<String, Function<MyClass, ? extends Comparable>> sortingOptions = new HashMap<>();
You will probably have to live with warnings, one at the sortingOptions
, another at list.sort()
.
If you want this to be neater, you can make a helper method.
@SuppressWarnings("unchecked")
private <T, U extends Comparable<U>> Function<? super T, ? extends U> getComparator(String sortBy) {
return (Function<T, U>) sortingOptions.get(sortBy);
}
Usage:
list.sort(Comparator.comparing(getComparator(sortBy)));
You should do what Clinton recommended, that approach is more clean.
Upvotes: -1
Reputation: 344
It may be easier to simply store the method references in your Map rather than the Functions that you have now. Consider this...
public class BaseClass implements Comparable<BaseClass> {
@Override
public int compareTo(BaseClass o) {
// implement this properly
return 0;
}
}
public class MyClass extends BaseClass {
private String attr1;
private Date attr2;
private ChildClass attr3;
//getter and setter
}
public class ChildClass extends BaseClass
{
private String attr1;
private Date attr2;
private int attr3;
//getter and setter
}
private List<MyClass> list;
private Map<String, Comparator<? super MyClass>> sortingOptions = new HashMap<>();
private String sortBy; //sorting attribute selected by user
@PostConstruct
public void init()
{
//my list to be sort
list = myService.getList();
sortingOptions.put("attr1", Comparator.comparing(MyClass::getAttr1));
sortingOptions.put("attr2", Comparator.comparing(MyClass::getAttr2));
sortingOptions.put("attr3", Comparator.comparing(MyClass::getAttr3));
//......
}
public void sortOptionChangedListener()
{
list.sort(sortingOptions.get(sortBy));
}
Upvotes: 8