Java Comparator.comparing比較導致空指針異常的解決
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,靜態方法中的泛型是根據傳的參數中的類型來決定的
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Java stream sorted使用 Comparator 進行多字段排序的方法
- 深入淺出講解Java8函數式編程
- java8 stream多字段排序的實現
- Java8-Stream流操作List去重問題
- java8 stream的多字段排序實現(踩坑)