欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java8排序

程序员文章站 2022-05-05 08:54:57
...

环境

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}

符合要求。

相关标签: java8 java java8