【问题标题】:Dynamically sort a list based on attribute selected by user in Java 8根据用户在 Java 8 中选择的属性对列表进行动态排序
【发布时间】:2018-07-20 11:31:27
【问题描述】:

我正在尝试使用Comparator.comparing() 对其成员属性进行排序,并且该属性由用户选择。考虑以下情况:

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 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 method comparing(Function<? super T,? extends U>) in the type Comparator is not applicable for the arguments (Function<MyClass,capture#3-of ?>)

【问题讨论】:

    标签: java sorting java-8


    【解决方案1】:

    将方法引用简单地存储在您的 Map 中可能比您现在拥有的 Functions 更容易。考虑一下...

    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));
    }
    

    【讨论】:

    • 清除解决方案。但是没有理由BaseClass 应该实现Comparable&lt;BaseClass&gt;;代码运行良好,没有。
    • 这是不正确的。 MyClass 的 attr3 是 ChildClass。如果 ChildClass 在某种程度上不是 Comparable,那么代码将无法编译。试试看。
    • 那么你应该使ChildClass具有可比性,而不是BaseClass。但是由于该问题不包含MyClass::getAttr3 作为排序标准,它提出了一个问题,它是否真的应该是这样,而不是例如Comparator.comparing(o -&gt; getAttr3().getAttr1())Comparator.comparing(o -&gt; getAttr3().getAttr2()) 等。强制 BaseClassComparable 与按属性排序的明显意图相矛盾。如果ChildClass 应该具有自然顺序,那么它已经是Comparable
    【解决方案2】:

    我不认为克林顿是对的。以下是 Comparator::comparing 源码。

    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));
    }
    

    它的参数是一个函数,输入参数是T,返回值是Comparable,这不适用于简单的getter。我认为反射可以做到这一点,但更复杂。

    【讨论】:

    • 正确。试试看。比较方法将返回 MyClass 的比较器。它所需要的只是一个函数,当给定一个 MyClass 对象时,它将产生任何其他 Comparable 对象。
    • 是的,你是对的。之前对 Function 的理解是错误的。非常感谢您的回答。
    【解决方案3】:

    你可以这样做:

    private Map<String, Function<MyClass, ? extends Comparable>> sortingOptions = new HashMap<>();
    

    您可能不得不忍受警告,一个在sortingOptions,另一个在list.sort()

    如果你想让它更整洁,你可以做一个辅助方法。

    @SuppressWarnings("unchecked")
    private <T, U extends Comparable<U>> Function<? super T, ? extends U> getComparator(String sortBy) {
        return (Function<T, U>) sortingOptions.get(sortBy);
    }
    

    用法:

    list.sort(Comparator.comparing(getComparator(sortBy)));
    

    更新

    你应该按照克林顿的建议去做,这种方法更干净。

    【讨论】:

      猜你喜欢
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 2012-02-08
      • 2020-08-16
      • 2015-09-06
      • 2021-06-27
      • 1970-01-01
      相关资源
      最近更新 更多