背景
有一个Map<String, String>
组成的列表mapList
,需要根据每个map
的name
值倒序排序。
创建一个根据Map<String, String>
中name
值倒序排序的Comparator
。
如果正序排序,可以这样写:
mapList.sort(Comparator.comparing(map -> map.get("name")));
但是如果倒序直接这样写,是会报错的:
mapList.sort(Comparator.comparing(map -> map.get("name")).reverse()); // 错误
报错:Cannot resolve method 'get' in 'Object'
,可以看出是变量map
被当做Object
了。
原因
其实问题的根源在泛型问题上。先看这一句:
Comparator.comparing(map -> map.get("name"));
如果单独这么写一句,是会报错的,原因是不知道变量map
的类型,自然会将其当做Object
,无法调用get
方法。
要明确指出变量map
的类型,有三种方法:
// 方法1:显式声明lambda
Function<Map<String, String>, String> keyExtractor = map -> map.get("name");
Comparator.comparing(keyExtractor);
方法1先声明了keyExtractor
的类型,明确指出了参数的类型。
// 方法2:指定Comparator的类型
Comparator<Map<String, String>> comparator = Comparator.comparing(map -> map.get("name"));
方法2指定了返回的Comparator
的类型,也能确定参数的类型。
comparing
函数的声明如下:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor) {...}
可以看到泛型T在返回值和参数中都出现,因此明确指定其中一个即可将其确定。
背景中的正序排序写法其实也是指定了返回值的类型,因为mapList.sort()
的参数一定是Comparator<Map<String, String>>
。
而倒序排序的写法在comparing
的返回值调用了reverse()
,就变成了返回值和参数都没指定类型,无法确定map
的类型了。
// 方法3:强制转换lambda的类型
Comparator.comparing((Function<Map<String, String>, String>) map -> map.get("name"));
方法3通过强制转换确定了comparing
函数参数的类型。
结论
// 倒序排序:实际使用中,建议写两行
mapList.sort(Comparator.comparing(map -> map.get("name")));
Collections.reverse(mapList);
// 如果想一行搞定,需要这么写
mapList.sort(Comparator.comparing((Function<Map<String, String>, String>) map -> map.get("name")).reverse());
// 顺带一提,如果是调用对象方法的话,用方法引用也可以搞定
userList.sort(Comparator.comparing(User::getName).reversed());