Java Comparator.comparing比較導(dǎo)致空指針異常
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)將報(bào)空指針異常
替代方案
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)); }
會(huì)先取出keyExtractor.apply(c1)和keyExtractor.apply(c2),放入比較器進(jìn)行比較
而Comparator.nullsFirst作為比較器,會(huì)創(chuàng)建一個(gè)Comparators.NullComparator比較器
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(true, comparator); }
Comparators.NullComparator比較器的compare接口實(shí)現(xiàn)中先進(jìn)行空值判斷處理,不為空的再進(jìn)行代入比較器比較
/** * 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方法的學(xué)習(xí)
例子:
我們需要根據(jù)對(duì)象中的name字段進(jìn)行不規(guī)則排序
排序規(guī)則為(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("商業(yè)", 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.實(shí)現(xiàn)
comparing方法有兩種實(shí)現(xiàn)
方法1:只有一個(gè)參數(shù),參數(shù)的類(lèi)型是一個(gè)函數(shù)式接口
方法2:
問(wèn):這個(gè)方法中泛型是怎么傳遞的
1、list.stream()時(shí),獲取的stream流已經(jīng)確定了泛型了,此時(shí)返回的對(duì)象為Stream<Obj>
2、Stream對(duì)象的sorted方法,需要比較器的類(lèi)型需要是Obj.calss或者是Obj的父類(lèi)
3、而我們這邊調(diào)用了靜態(tài)方法Comparator.comparing,靜態(tài)方法中的泛型是根據(jù)傳的參數(shù)中的類(lèi)型來(lái)決定的
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://wanghq.blog.csdn.net/article/details/108050952