java - 通用对象映射的顺序元素---通过对象的通用属性---Lamda - Java
问题描述
我需要一种方法来通过对象的通用属性对通用对象的 Map 进行排序。我尝试了下面的代码,类似于我在 StackOverFlow 上找到的其他示例,但我没有找到任何具有通用属性的示例。我不是lamda的专家,所以对我来说很难清楚地理解一些逻辑。
我在 compareTo 上收到错误;Ntebeans 对我说:
“找不到符号符号:方法 compareTo(CAP#1) 位置:类对象,其中 CAP#1 是一个新的类型变量:CAP#1 从捕获中扩展对象?”
例子:
- 我有一个带有属性“名称”的对象“汽车”
- 我有一个 Hashmap<Integer,car>,包含项目:键 1,名称为福特的对象 --- 键 2,名称为奥迪的对象 --- 键 3,名称为菲亚特的对象
- map 的第一个元素有 key 1,第二个有 key 2,第三个有 key 3
- 我想在输出中有一个 Arraylist,其中: - 第一个元素是对象“Audi”,第二个是对象“Fiat”,第三个是对象“Ford”,因此要对 3 个名称进行排序。
为了调用此方法,我将使用例如:
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;
}
解决方案
给定您的代码(为清晰起见进行了重构)
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 String
which implementsComparable
并因此具有compareTo
方法实现。
关于您的代码的注释(我的观点)
- 当使用返回
Collection
像您这样的类型的方法时,如果这样的方法返回null
而不是空集合,那将是非常令人惊讶的——这将是许多(也令人惊讶)NullPointerException
的原因。 - 正如评论中所指出的,
aMap.values() != null
总是true
因为(惊讶)Java API 设计者/实现者决定这个方法应该总是返回一个非空集合,即如果没有值则返回一个空集合。无论如何,该条件无效,它始终是true
. aMap != null
并且attributeValueExtractor != null
,只需 throw 而是因为使用null
参数调用您的方法根本不应该是允许继续的有效调用(快速失败原则)。aMap.size() > 0
并不是真正需要的,因为后续的流代码可以毫无问题地处理它,即结果只是一个空列表。并且故意null
为这种情况而恢复并不是我每个人都会做的事情(如上所述)。- 不要吞下异常,要么抛出(快速失败原则)要么有意义地恢复。
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());
}
推荐阅读
- c# - Blazor 数据库连接到远程 mysql 服务器
- macos - Python 任务在更新后关闭 VSCode 时启动
- scrum - 哪个是最受认可的 Scrum Master 认证?
- matlab - 使用matlab计算并绘制一组弹性数据
- css - 尺寸正确显示在 html 屏幕上。但在 React 中,大小不合适
- cors - Cloud Run 是否会从我的后端移除 CORS 标头?
- javascript - 当我单击该弹出窗口内的编辑按钮时,我想使用输入字段调用相同的弹出窗口,我该怎么做(如果可能)?
- r - 在 rhandsontable Shiny 环境中使用 dplyr mutate
- javascript - Discord.JS 附件 URL / 图片问题
- python - Python Selenium 写入 excel