首页 > 解决方案 > 通用对象映射的顺序元素---通过对象的通用属性---Lamda - Java

问题描述

我需要一种方法来通过对象的通用属性对通用对象的 Map 进行排序。我尝试了下面的代码,类似于我在 StackOverFlow 上找到的其他示例,但我没有找到任何具有通用属性的示例。我不是lamda的专家,所以对我来说很难清楚地理解一些逻辑。

我在 compareTo 上收到错误;Ntebeans 对我说:

“找不到符号符号:方法 compareTo(CAP#1) 位置:类对象,其中 CAP#1 是一个新的类型变量:CAP#1 从捕获中扩展对象?”

例子:

为了调用此方法,我将使用例如:

ArrayList<Car> SORTED_Cars = get_ListOfObject_SortedByAttribute(myHashMap, car -> car.getName() );

我应该得到一个按属性“名称”排序的对象“汽车”的 ArrayList。

最后的任务是有一个方法,我将使用不同对象的映射,然后使用不同的属性。

请注意,我使用此检查条件

if (MyMap_Arg!=null &&  MyMap_Arg.size()>0 && MyMap_Arg.values()!=null)

因为当无法排序或地图为空时,我更喜欢获取 null 。

下面的代码应该如何工作?

        private static <T> List<T> get_ListOfObject_SortedByAttribute(final Map<?, T> MyMap_Arg,       final Function<T, ?> MY_AttributeValueExtractor__Arg     ) {
        List<T> result = null;
        try {
            if (MyMap_Arg!=null &&  MyMap_Arg.size()>0 && MyMap_Arg.values()!=null){
                if (MY_AttributeValueExtractor__Arg!=null ) {
                    
                    //_____________________________________________________
                    //Crea una lista di oggetti che hanno MY_AttributeValueExtractor_1_Arg!=null; altrimenti applicando '.compare' darebbe exception
                    List<T> MY_LIST__SenzaNull =  MyMap_Arg.values().stream().filter(    o -> MY_AttributeValueExtractor__Arg.apply(o)!=null   ).collect(Collectors.toList()); 
                        
                    //_____________________________________________________
                    //TEST  ********* Ordina la lista di oggetti alfabeticamente in base a MY_AttributeValueExtractor_1_Arg
                    result = MY_LIST__SenzaNull.stream().sorted(  
                        (o1, o2)->  MY_AttributeValueExtractor__Arg.apply(o1).
                        compareTo(  MY_AttributeValueExtractor__Arg.apply(o2)  )  
                            
                    ).
                    collect(Collectors.toList());                        
                        
                    //_____________________________________________________
                        
                } 
            }
        } catch (Exception ex) {
            result=null;
        }
        return result;
    }    

标签: javalambda

解决方案


给定您的代码(为清晰起见进行了重构)

static <T> List<T> getListSortedByAttribute(Map<?, T> aMap,
                                       Function<T, ?> attributeValueExtractor) {

    List<T> result = null;
    try {
        if (aMap != null && aMap.size() > 0 && aMap.values() != null) {
            if (attributeValueExtractor != null) {

                List<T> listWithoutElementsReturingNullAsAttributeValue = aMap
                        .values()
                        .stream()
                        .filter(o -> attributeValueExtractor.apply(o) != null)
                        .collect(Collectors.toList());

                result = listWithoutElementsReturingNullAsAttributeValue
                        .stream()
                        .sorted((o1, o2) -> attributeValueExtractor.apply(o1).
                                compareTo(attributeValueExtractor.apply(o2)))
                        .collect(Collectors.toList());
            }
        }
    } catch (Exception ex) {
        result = null;
    }
    return result;
}

您想使用一种方法通过作为函数给出的属性compareTo之一来比较(排序)列表元素

(o1, o2) -> attributeValueExtractor.apply(o1)
                                   .compareTo(attributeValueExtractor.apply(o2))

使用它你会得到编译时错误

Error:(149, 78) java: cannot find symbol
  symbol:   method compareTo(capture#1 of ?)
  location: class java.lang.Object

意思是,您的代码中没有任何内容可以确保您的属性具有这样的方法(并且可以进行比较以进行排序)。特别是,Function<T, ?> attributeValueExtractor)表示某些类型T(通过您的函数)映射到?只能是Object; 并且Object没有compareTo方法。(请注意,Object没有这样的方法,因为根本没有任何有意义的方法可以相互比较任意对象)。

要修复它(至少),您需要确保您的对象实现这样的方法。所以你的方法签名

static <T> List<T> getListSortedByAttribute(
                          Map<?, T> aMap, Function<T, ?> attributeValueExtractor)

需要更改为

static <T, U extends Comparable<U>> List<T> getListSortedByAttribute(
                          Map<?, T> aMap, Function<T, U> attributeValueExtractor)

其中U需要类型来实现Comparable具有方法的接口compareTo

这样你就得到了(再加上一些重构和一个例子)

public static void main(String[] args) {
    Map<Integer, Car> map = new HashMap<>();
    map.put(1, new Car("Ford"));
    map.put(2, new Car("Audi"));
    map.put(3, new Car("Fiat"));
    map.put(4, new Car(null));

    List<Car> list = getListSortedByAttribute(map, Car::getName);
    System.out.println(list);
}

static <T, U extends Comparable<U>> List<T> getSortedValues(
                   Map<?, T> aMap, Function<T, U> attributeExtractor) {

    List<T> result = null;
    try {
        if (aMap != null && aMap.size() > 0) {
            if (attributeExtractor != null) {
                result = aMap
                          .values()
                          .stream()
                          .filter(o -> attributeExtractor.apply(o) != null)
                          .sorted((o1, o2) -> attributeExtractor.apply(o1).
                                compareTo(attributeExtractor.apply(o2)))
                          .collect(Collectors.toList());
            }
        }
    } catch (Exception ex) {
        result = null;
    }
    return result;
}

static class Car {
    private final String name;

    Car(String name) { this.name = name; }

    String getName() { return name; }

    @Override
    public String toString() { return name; }

    // code for equals() and hashCode() omitted for brevity
}

哪个打印

[Audi, Fiat, Ford]

至于List<Car> list = getListSortedByAttribute(map, Car::getName);注意,您可以使用 lambda 表达式(Car car) -> car.getName()方法引用 Car::getName作为方法参数。我选择了后者,因为我发现它更短。

然后调用起作用,因为返回类型Car::getName是 a Stringwhich implementsComparable并因此具有compareTo方法实现。

关于您的代码的注释(我的观点)

  1. 当使用返回Collection像您这样的类型的方法时,如果这样的方法返回null而不是空集合,那将是非常令人惊讶的——这将是许多(也令人惊讶)NullPointerException的原因。
  2. 正如评论中所指出的,aMap.values() != null总是true因为(惊讶)Java API 设计者/实现者决定这个方法应该总是返回一个非空集合,即如果没有值则返回一个空集合。无论如何,该条件无效,它始终是true.
  3. aMap != null并且attributeValueExtractor != null,只需 throw 而是因为使用null参数调用您的方法根本不应该是允许继续的有效调用(快速失败原则)。
  4. aMap.size() > 0并不是真正需要的,因为后续的流代码可以毫无问题地处理它,即结果只是一个空列表。并且故意null为这种情况而恢复并不是我每个人都会做的事情(如上所述)。
  5. 不要吞下异常,要么抛出(快速失败原则)要么有意义地恢复。null但如上所述的回归并不是有意义的复苏。

关于上述和进一步的变化,你会得到

static <T, U extends Comparable<U>> List<T> getSortedValues(
                   Map<?, T> aMap, Function<T, U> attributeExtractor) {

    Objects.requireNonNull(aMap, "Map to be sorted cannot be null");
    Objects.requireNonNull(attributeExtractor, "Function to extract a value cannot be null");

    return aMap
            .values()
            .stream()
            .filter(o -> attributeExtractor.apply(o) != null)
            .sorted(Comparator.comparing(attributeExtractor))
            .collect(Collectors.toList());
}

推荐阅读