Java Comparator.comparing比较导致空指针异常
Comparator.comparing(Department::getOrder)
原因:
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)); }
如果keyExtractor.apply(c1),那么keyExtractor.apply(c1).compareTo(XX)将报空指针异常
替代方案
Comparator.comparing(Department::getOrder, Comparator.nullsFirst(Comparator.naturalOrder()))
替代方案好处:
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)); }
会先取出keyExtractor.apply(c1)和keyExtractor.apply(c2),放入比较器进行比较
而Comparator.nullsFirst作为比较器,会创建一个Comparators.NullComparator比较器
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(true, comparator); }
Comparators.NullComparator比较器的compare接口实现中先进行空值判断处理,不为空的再进行代入比较器比较
/** * Null-friendly comparators */ final static class NullComparator<T> implements Comparator<T>, Serializable { private static final long serialVersionUID = -7569533591570686392L; private final boolean nullFirst; // if null, non-null Ts are considered equal private final Comparator<T> real; @SuppressWarnings("unchecked") NullComparator(boolean nullFirst, Comparator<? super T> real) { this.nullFirst = nullFirst; this.real = (Comparator<T>) real; } @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); } } @Override public Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other)); } @Override public Comparator<T> reversed() { return new NullComparator<>(!nullFirst, real == null ? null : real.reversed()); } }
Comparator中comparing方法的学习
例子:
我们需要根据对象中的name字段进行不规则排序
排序规则为(PPD > 政府 > 合作)
public class Obj { private String name; private BigDecimal price; ...... }
@Test public void sort() { List<Obj> list = Arrays.asList( new Obj("政府", null), new Obj("政府", new BigDecimal("1216.23")), new Obj("商业", new BigDecimal("123.23")), new Obj("PPD", new BigDecimal("123.23")), new Obj("合作", new BigDecimal("127.23")), new Obj(null, new BigDecimal("125.23"))); List<String> sortList = Arrays.asList("PPD","政府","合作"); List<Obj> result = list.stream().sorted( //先按照name排序(模拟需求的a属性排序) Comparator.comparing(Obj::getName,(x,y)-> { if(x == null && y != null){ return 1; }else if(x !=null && y == null){ return -1; }else if(x == null && y == null){ return -1; } else { for(String sort : sortList){ if(sort.equals(x) || sort.equals(y)){ if(x.equals(y)){ return 0; }else if(sort.equals(x)){ return -1; }else{ return 1; } } } return 0; } })).collect(Collectors.toList()); System.out.println(result); }
1.实现
comparing方法有两种实现
方法1:只有一个参数,参数的类型是一个函数式接口
方法2:
问:这个方法中泛型是怎么传递的
1、list.stream()时,获取的stream流已经确定了泛型了,此时返回的对象为Stream<Obj>
2、Stream对象的sorted方法,需要比较器的类型需要是Obj.calss或者是Obj的父类
3、而我们这边调用了静态方法Comparator.comparing,静态方法中的泛型是根据传的参数中的类型来决定的
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。