Java Comparator的范型类型推导问题
问题
在项目中,有一处地方需要对日期区间进行排序
我需要以日期区间的开始日为第一优先级,结束日为第二优先级进行排序
代码
我当时写的代码如下:
List<Pair<LocalDate, LocalDate>> dateIntervals = new ArrayList<>();
// 省略构造日期区间
dateIntervals.sort(Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight));
这段看上去很正确的代码,居然是没办法编译的。
做了一些试验
dateIntervals.sort(Comparator.comparing(Pair::getLeft));
当仅以日期开始日排序,可以编译没问题
那么把Comparator单独提取出来呢
Comparator<Pair<LocalDate, LocalDate>> cmp = Comparator.comparing(Pair::getLeft);
dateIntervals.sort(cmp);
这样当然是没有问题的
Comparator<Pair<LocalDate, LocalDate>> cmp = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);
dateIntervals.sort(cmp);
这样是没法编译的,和我原来的写法其实没有本质的区别
Comparator<Pair<LocalDate, LocalDate>> cmp = Comparator.comparing(Pair::getLeft);
cmp = cmp.thenComparing(Pair::getRight);
dateIntervals.sort(cmp);
当我再尝试把thenComparing分开来写时,居然又可以通过编译了
对此我感到很困惑,我在伟大万能的stackoverflow上翻到了一个类似的问题
这个哥们碰到的问题与我的问题虽然不是同一个,但却是类似的。
本质的问题是Java语言的类型推导
来看一下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));
}
再来看一下Comparator#thenComparing
的源码
default <U extends Comparable<? super U>> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor)
{
return thenComparing(comparing(keyExtractor));
}
好的,再回顾一下下面这段可以通过编译的代码
Comparator<Pair<LocalDate, LocalDate>> cmp = Comparator.comparing(Pair::getLeft);
dateIntervals.sort(cmp);
由于dateIntervals
是List<Pair<LocalDate,LocalDate>>
类型,Java编译器可以根据这个目标类型来进行推导,所以sort函数内的Comparator.comparing
应该返回的是Comparator<Pair<LocalDate,LocalDate>>
,那么comparing内的函数的入参是Pair<LocalDate,LocalDate>就确定下来了。
再来看一下不能编译的如下代码
Comparator<Pair<LocalDate, LocalDate>> cmp = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);
dateIntervals.sort(cmp);
问题是thenComparing
返回的Comparator<T>
中的T是跟着调用方走的,也就是意味着要得先知道前面一部分 Comparator.comparing(Pair::getLeft)
的类型,但是这种情况下前面这一部分没办法根据目标类型进行推导,所以类型推导在这里就陷入了一种僵局。
这不得不说是Java语言中类型推导还不够完美的地方。
那么如何解决这个问题呢,除了上面那种Comparator分两步走的情况,
直接指定范型类型来调用方法,专治各种范型推导失败。
关于指定范型类型调用方法的语法规范可以参考JLS 15.12中写明的方法调用。
所以,最后我写的语句是如下的:
dateIntervals.sort(Comparator.<Pair<LocalDate, LocalDate>, LocalDate>comparing(Pair::getLeft) .thenComparing(Pair::getRight));
Java Comparator的范型类型推导问题的更多相关文章
- Java数据结构与算法分析-第一章(引论)-Java中的范型<T,E>构件
一.为什么需要使用范型? 官方的说法是:Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质 ...
- Java范型
泛型不用考虑对象的具体类型.优点在于,因为不用考虑对象的具体类型所以可以对一类对象执行一定的相同操作:缺点在于,因为没有考虑对象的具体类型所以就不能使用对象自带的接口函数.泛型的最佳用同是实现容器类. ...
- 关于java范型
1 范型只在编译阶段有效 编译器在编译阶段检查范型结果之后,就会将范型信息删除.范型信息不会进入运行时阶段. 泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型. 2 不能对确定的范型 ...
- C# 范型约束 new() 你必须要知道的事
C# 范型约束 new() 你必须要知道的事 注意:本文不会讲范型如何使用,关于范型的概念和范型约束的使用请移步谷歌. 本文要讲的是关于范型约束无参构造函数 new 的一些底层细节和注意事项.写这篇文 ...
- Java范型随笔
最近在帝都好无聊啊, 排遣寂寞就只有让自己不要停下来,不断的思考了 QWQ; 最近做ndk, java有点忘了,突然看到了一些java范型方面的问题, 踌躇了一会, 想着想着,决定还是写个随笔记录下来 ...
- Java数组协变与范型不变性
变性是OOP语言不变的大坑,Java的数组协变就是其中的一口老坑.因为最近踩到了,便做一个记录.顺便也提一下范型的变性. 解释数组协变之前,先明确三个相关的概念,协变.不变和逆变. 一.协变.不变.逆 ...
- Java范型学习笔记
对于范型的使用或者说印象只有集合,其他地方即使使用过也不知道,反正就是只停留在List<E> Map<K, V>,最近刚好闲来无事,就找找资料学习一下:下列为个人学习总结,欢迎 ...
- 为什么Java不允许创建范型数组
问题示例 List<Integer>[] intListArr = new ArrayList<Integer>[8]; // 编译时报错 能看到这么看似没啥问题的一个简单语句 ...
- java范型集合中的成员排序
范型集合中的类是JsonObject,不是自定义类,如果是自定义类就直接取要比较的字段值. ArrayList<JSONObject> TList = new ArrayList<J ...
随机推荐
- Objective-C日记-之NSPredicate
谓语:NSPredicate 1,概述: 用于设置指定的过滤器的条件,通俗的理解就是设置选择的条件,再对指定的对象应用这个条件 2,用法: a,首先设置谓语. NSPredicate *predica ...
- 获取bing图片并自动设置为电脑桌面背景(C++完整开源程序)
众所周知,bing搜索网站首页每日会更新一张图片,张张漂亮(额,也有一些不合我口味的),特别适合用来做电脑壁纸. 我们想要将bing网站背景图片设置为电脑桌面背景的通常做法是: 上网,搜索bing 找 ...
- 3297: [USACO2011 Open]forgot
3297: [USACO2011 Open]forgot Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 69 Solved: 51[Submit][ ...
- 来谈一谈------JavaScript对象
1.window常用的属性: ①history ②location 2.history对象的方法: ①back() ②forward() ③go() 3.location对象的属性: ①host() ...
- yii2.0下拉列表的使用
第一种方法:ActiveForm 类的 dropDownList 方法(优点,默认使用yii的样式) 1.在控制器的方法里面 ,我们需要拿到数据,一定是 findAll() 或者是 all() 方法的 ...
- Python中 sys.argv[]的用法
Python中 sys.argv[]的用法 因为是看书自学的python,开始后不久就遇到了这个引入的模块函数,且一直在IDLE上编辑了后运行,试图从结果发现它的用途,然而结果一直都是没结果,也在网上 ...
- 移动web页面支持弹性滚动的3个方案
有段时间一直折腾移动端页面弹性滚动的各种问题,做了点研究,今天做个小分享~ 传统 pc 端中,子容器高度超出父容器高度,通常使用 overflow:auto 可出现滚动条拖动显示溢出的内容,而移动we ...
- 【前端调试手机页面】分享一款便捷的调试工具--spy-debugger
spy-debugger : 微信调试,各种WebView样式调试.手机浏览器的页面真机调试.便捷的远程调试手机页面.抓包工具,支持:HTTP/HTTPS,无需USB连接设备. github地址: ...
- 数字千分位处理,number.js,js保留两位,整数强制保留两位小数
杨龙飞 杨龙飞 杨龙飞 杨龙飞 杨龙飞 杨龙飞 官方文档:https://www.customd.com/articles/14/jquery-number-format-redux 1.千分位 $. ...
- 【Hexo】(一)使用HEXO配置环境,创建Hello World
现场直播,呵呵,就是我完成一步,就记录一下: 一.配置环境 1.安装 Node 下载地址:Node.js 2.安装 Git(win环境下) 下载地址:Git Git 绑定 GitHub账户: ①打开G ...