java comparator泛型_Java Comparator的范型类型推导问题

问题

在项目中,有一处地方需要对日期区间进行排序

我需要以日期区间的开始日为第一优先级,结束日为第二优先级进行排序

代码

我当时写的代码如下:

List> dateIntervals = new ArrayList<>();

// 省略构造日期区间

dateIntervals.sort(Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight));

这段看上去很正确的代码,居然是没办法编译的。

做了一些试验

dateIntervals.sort(Comparator.comparing(Pair::getLeft));

当仅以日期开始日排序,可以编译没问题

那么把Comparator单独提取出来呢

Comparator> cmp = Comparator.comparing(Pair::getLeft);

dateIntervals.sort(cmp);

这样当然是没有问题的

Comparator> cmp = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);

dateIntervals.sort(cmp);

这样是没法编译的,和我原来的写法其实没有本质的区别

Comparator> cmp = Comparator.comparing(Pair::getLeft);

cmp = cmp.thenComparing(Pair::getRight);

dateIntervals.sort(cmp);

当我再尝试把thenComparing分开来写时,居然又可以通过编译了

对此我感到很困惑,我在伟大万能的stackoverflow上翻到了一个类似的问题

这个哥们碰到的问题与我的问题虽然不是同一个,但却是类似的。

本质的问题是Java语言的类型推导

来看一下Comparator#comparing的源码

public static > Comparator comparing(

Function super T, ? extends U> keyExtractor)

{

Objects.requireNonNull(keyExtractor);

return (Comparator & Serializable)

(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));

}

再来看一下Comparator#thenComparing的源码

default > Comparator thenComparing(

Function super T, ? extends U> keyExtractor)

{

return thenComparing(comparing(keyExtractor));

}

好的,再回顾一下下面这段可以通过编译的代码

Comparator> cmp = Comparator.comparing(Pair::getLeft);

dateIntervals.sort(cmp);

由于dateIntervals是List>类型,Java编译器可以根据这个目标类型来进行推导,所以sort函数内的Comparator.comparing应该返回的是Comparator>,那么comparing内的函数的入参是Pair就确定下来了。

再来看一下不能编译的如下代码

Comparator> cmp = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);

dateIntervals.sort(cmp);

问题是thenComparing返回的Comparator中的T是跟着调用方走的,也就是意味着要得先知道前面一部分Comparator.comparing(Pair::getLeft)的类型,但是这种情况下前面这一部分没办法根据目标类型进行推导,所以类型推导在这里就陷入了一种僵局。

这不得不说是Java语言中类型推导还不够完美的地方。

那么如何解决这个问题呢,除了上面那种Comparator分两步走的情况,

直接指定范型类型来调用方法,专治各种范型推导失败。

关于指定范型类型调用方法的语法规范可以参考JLS 15.12中写明的方法调用。

所以,最后我写的语句是如下的:

dateIntervals.sort(Comparator., LocalDate>comparing(Pair::getLeft) .thenComparing(Pair::getRight));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,Comparator接口用于定义两个对象的比较方式。Comparator接口中只有一个方法,即compare(Object o1, Object o2),该方法返回一个int类型值,表示两个对象之间的大小关系。 在Java中,我们可以使用Comparator接口对集合中的元素进行排序。具体来说,我们可以使用Collections.sort()方法对List进行排序,该方法接收一个Comparator类型的参数来指定排序的方式。 Comparator接口中的compare方法的返回值代表了两个对象之间的大小关系。当compare方法返回负数时,表示o1小于o2;当compare方法返回正数时,表示o1大于o2;当compare方法返回0时,表示o1等于o2。 下面是一个使用Comparator接口对List进行排序的例子: ``` List<Integer> list = new ArrayList<>(); list.add(3); list.add(1); list.add(2); Collections.sort(list, new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { return o1 - o2; } }); ``` 在这个例子中,我们创建了一个包含三个整数的List,并使用Collections.sort()方法对其进行排序。我们使用了一个匿名内部类来实现Comparator接口,将整数按升序排序。 在Java中,Comparator接口的实现方式有很多种,例如可以使用Lambda表达式、Comparator.comparing()方法、Comparator.thenComparing()方法等。这些方法都可以帮助我们更方便地实现Comparator接口。 总之,Comparator接口是Java中非常重要的一个接口,它提供了一种灵活的方法来对集合中的元素进行排序。熟练掌握Comparator接口的使用方法可以让我们更好地处理集合数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值