Java8学习笔记:排序

环境

Java8

数据准备

非完整代码:

List<Map<String, Object>> result = new ArrayList<>();
map1.put("created", null);
map2.put("created", 1578394193000);
map3.put("created", 1578394183000);
map4.put("created", 1578394173000);
map5.put("created", null);

上面每个map还有nameskuId等字段。

null排在前面

这里,我曾经犯了个错,记录下:

public static void main(String[] args) {
    List<Map<String, Object>> result = new ArrayList<>();
    Map<String, Object> map1 = new HashMap<>();
    map1.put("created", null);
    Map<String, Object> map2 = new HashMap<>();
    map2.put("created", Instant.ofEpochMilli(1578394193000L).atOffset(ZoneOffset.of("+8")));
    Map<String, Object> map3 = new HashMap<>();
    map3.put("created", Instant.ofEpochMilli(1578394183000L).atOffset(ZoneOffset.of("+8")));
    Map<String, Object> map4 = new HashMap<>();

    map4.put("created", Instant.ofEpochMilli(1578394173000L).atOffset(ZoneOffset.of("+8")));
    Map<String, Object> map5 = new HashMap<>();
    map5.put("created", null);

    result.add(map1);
    result.add(map2);
    result.add(map3);
    result.add(map4);
    result.add(map5);
    
    // 错误
    List<Map<String, Object>> errorList = result.stream()
        .sorted(nullsFirst(comparing(map -> (OffsetDateTime) map.get("created"))))
        .collect(Collectors.toList());

    for (Map<String, Object> map : mapList) {
        System.out.println(map);
    }
}

上面代码执行后,会报NPE异常。
分析下原因:
看下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));
 }

当遇到null元素时,keyExtractor.apply(c1)就会返回null,接着又去调compareTo()方法时,就报NPE异常了。

正确的代码:

 // 正确
 List<Map<String, Object>> mapList = result.stream()
         .sorted(comparing(map -> (OffsetDateTime)map.get("created"), nullsFirst(OffsetDateTime::compareTo)))
         .collect(Collectors.toList());

而这段代码不报异常的原因:

先看下comparing()方法的源码:

public static <T, U> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor,
        Comparator<? super U> keyComparator)
{
    Objects.requireNonNull(keyExtractor);
    Objects.requireNonNull(keyComparator);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                          keyExtractor.apply(c2));
}

当代码执行到:

(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                          keyExtractor.apply(c2))

会执行Comparators类中的compare()方法:

@Override
public int compare(T a, T b) {
    if (a == null) {
        return (b == null) ? 0 : (nullFirst ? -1 : 1);
    } else if (b == null) {
        return nullFirst ? 1: -1;
    } else {
        return (real == null) ? 0 : real.compare(a, b);
    }
}

可以看到,这个方法加了空判断。

当执行到real.compare(a, b)这个方法的时候,就会去执行我们传入的方法引用OffsetDateTime::compareTo

降序并且null排在前面

刚开始我是这么写的:

List<Map<String, Object>> mapList = result.stream()
        .sorted(comparing(map -> (OffsetDateTime)map.get("created"), 
                nullsFirst(OffsetDateTime::compareTo).reversed()))
        .collect(Collectors.toList());

但是这样的会,结果就是:

{created=2020-01-07T18:49:53+08:00}
{created=2020-01-07T18:49:43+08:00}
{created=2020-01-07T18:49:33+08:00}
{created=null}
{created=null}

降是降序了,但是null缺跑最后去了。

看下源码

nullsFirst(OffsetDateTime::compareTo)

上面那段代码点进去后:

public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(true, comparator);
}

我们再看下Comparators类中reversed()方法:

@Override
public Comparator<T> reversed() {
    return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());
}

发现reversed()方法第一个参数使用了!nullFirst

所以正确的写法应该是:

 // 正确
 List<Map<String, Object>> mapList = result.stream()
         .sorted(comparing(map -> (OffsetDateTime)map.get("created"),
                 nullsLast(OffsetDateTime::compareTo).reversed()))
         .collect(Collectors.toList());

结果:

{created=null}
{created=null}
{created=2020-01-07T18:49:53+08:00}
{created=2020-01-07T18:49:43+08:00}
{created=2020-01-07T18:49:33+08:00}

符合要求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值