本文主要學習了在Java1.8中新增的Collector介面和Collectors工具類,以及使用它們在處理集合時的改進和優化。 ...
JDK1.8新特性——Collector介面和Collectors工具類
摘要:本文主要學習了在Java1.8中新增的Collector介面和Collectors工具類,以及使用它們在處理集合時的改進和優化。
部分內容來自以下博客:
https://www.jianshu.com/p/7eaa0969b424
流式處理
JDK1.8中新增的流式處理提供了一種高效且易於使用的處理數據的方式,它可以對集合執行非常複雜的查找、過濾和映射數據等操作,極大的簡化了對於集合的使用。藉助流式處理,可以像使用SQL語句一樣對集合進行操作。
JDK1.8通過內部迭代來實現對流的處理,一個流式處理可以分為三個部分:轉換成流、中間操作、終止操作。
轉換成流
對於集合,可以使用集合類中的stream()方法或者parallelStream()方法將集合轉換成流。
中間操作
中間操作可以對流進行處理並返回處理後的流對象,多個中間操作可以連接起來形成一個流水線,直到執行終止操作結束流的執行。
終止操作
終止操作會對經過中間操作後得到的流進行處理,返回任何不是流的數據。
Collector介面
在對流進行的終止操作中,有一個方法是collect,其作用是收集元素併進行處理,最終返回處理後的非流對象。
查看其方法定義如下:
1 <R, A> R collect(Collector<? super T, A, R> collector);
可以看到,collect方法要求傳入一個Collector介面的實例對象,Collector可以看做是用來處理流的工具,在Collectors裡面封裝了很多Collector工具。
全局變數
Collector主要包含五個參數,它的行為也是由這五個參數來定義的,如下所示:
1 // supplier參數用於生成結果容器,容器類型為A。 2 Supplier<A> supplier(); 3 // accumulator用於歸納元素,泛型T就是元素,它會將流中的元素同結果容器A發生操作。 4 BiConsumer<A, T> accumulator(); 5 // combiner用於合併兩個並行執行的結果,將其合併為最終結果A。 6 BinaryOperator<A> combiner(); 7 // finisher用於將之前完整的結果R轉為A。 8 Function<A, R> finisher(); 9 // characteristics表示當前Collector的特征值,是一個不可變的Set。 10 Set<Characteristics> characteristics();
枚舉
Characteristics這個特征值是一個枚舉:
1 enum Characteristics { 2 // 多線程並行。 3 CONCURRENT, 4 // 無序。 5 UNORDERED, 6 // 無需轉換結果。 7 IDENTITY_FINISH 8 }
構造方法
Collector擁有兩個of方法用於生成Collector實例,其中一個擁有上面所有五個參數,另一個四個參數,不包括finisher參數。
1 // 四參方法,用於生成一個Collector,T代表流中的元素,R代表最終的結果。因為沒有finisher參數,所以需要有IDENTITY_FINISH特征值。 2 public static<T, R> Collector<T, R, R> of(Supplier<R> supplier, 3 BiConsumer<R, T> accumulator, 4 BinaryOperator<R> combiner, 5 Characteristics... characteristics) { 6 Objects.requireNonNull(supplier); 7 Objects.requireNonNull(accumulator); 8 Objects.requireNonNull(combiner); 9 Objects.requireNonNull(characteristics); 10 Set<Characteristics> cs = (characteristics.length == 0) 11 ? Collectors.CH_ID 12 : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH, 13 characteristics)); 14 return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs); 15 } 16 17 // 五參方法,用於生成一個Collector,T代表流中的元素,A代表中間結果,R代表最終結果,finisher用於將A轉換為R。 18 public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier, 19 BiConsumer<A, T> accumulator, 20 BinaryOperator<A> combiner, 21 Function<A, R> finisher, 22 Characteristics... characteristics) { 23 Objects.requireNonNull(supplier); 24 Objects.requireNonNull(accumulator); 25 Objects.requireNonNull(combiner); 26 Objects.requireNonNull(finisher); 27 Objects.requireNonNull(characteristics); 28 Set<Characteristics> cs = Collectors.CH_NOID; 29 if (characteristics.length > 0) { 30 cs = EnumSet.noneOf(Characteristics.class); 31 Collections.addAll(cs, characteristics); 32 cs = Collections.unmodifiableSet(cs); 33 } 34 return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs); 35 }
Collectors工具類
Collectors是一個工具類,是JDK預實現Collector的工具類,它內部提供了多種Collector。
toCollection方法
將流中的元素全部放置到一個集合中返回,這裡使用Collection,泛指多種集合。
方法:
1 public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) { 2 return new CollectorImpl<>( 3 collectionFactory, Collection<T>::add, 4 (r1, r2) -> { r1.addAll(r2); return r1; }, 5 CH_ID); 6 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 LinkedList<String> newList = list.stream().collect(Collectors.toCollection(LinkedList::new)); 5 System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345] 6 }
toList方法
將流中的元素放置到一個List集合中返回,預設為ArrayList。
方法:
1 public static <T> 2 Collector<T, ?, List<T>> toList() { 3 return new CollectorImpl<>( 4 (Supplier<List<T>>) ArrayList::new, List::add, 5 (left, right) -> { left.addAll(right); return left; }, 6 CH_ID); 7 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 List<String> newList = list.stream().collect(Collectors.toList()); 5 System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345] 6 }
toSet方法
將流中的元素放置到一個Set集合中返回,預設為HashSet。
方法:
1 public static <T> Collector<T, ?, Set<T>> toSet() { 2 return new CollectorImpl<>( 3 (Supplier<Set<T>>) HashSet::new, Set::add, 4 (left, right) -> { left.addAll(right); return left; }, 5 CH_UNORDERED_ID); 6 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Set<String> newSet = list.stream().collect(Collectors.toSet()); 5 System.out.println(newSet);// [100, 123, 521, 345, 228, 838, 250] 6 }
toMap方法
根據傳入的鍵生成器和值生成器,將生成的鍵和值保存到一個Map中返回,鍵和值的生成都依賴於元素,可以指定出現重覆鍵時的處理方案和保存結果的Map。
還有支持併發toConcurrentMap方法,同樣有三種重載方法,與toMap基本一致,只是它最後使用的Map是併發ConcurrentHashMap。
方法:
1 // 指定鍵和值的生成方式,遇到鍵衝突的情況預設拋出異常,預設使用HashMap。 2 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap( 3 Function<? super T, ? extends K> keyMapper, 4 Function<? super T, ? extends U> valueMapper) { 5 return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); 6 } 7 // 指定鍵和值的生成方式,遇到鍵衝突的情況使用傳入的方法處理,預設使用HashMap。 8 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap( 9 Function<? super T, ? extends K> keyMapper, 10 Function<? super T, ? extends U> valueMapper, 11 BinaryOperator<U> mergeFunction) { 12 return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); 13 } 14 // 指定鍵和值的生成方式,遇到鍵衝突的情況使用傳入的方法處理,使用傳入的Map類型返回數據。前兩種方式最終還是調用此方法來返回Map數據。 15 public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap( 16 Function<? super T, ? extends K> keyMapper, 17 Function<? super T, ? extends U> valueMapper, 18 BinaryOperator<U> mergeFunction, 19 Supplier<M> mapSupplier) { 20 BiConsumer<M, T> accumulator = (map, element) -> map.merge( 21 keyMapper.apply(element), 22 valueMapper.apply(element), 23 mergeFunction); 24 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); 25 }
實例:
1 public static void main(String[] args) { 2 Map<String, String> newMap = null; 3 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 4 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 5 // 123和100的鍵都是1,導致衝突,預設拋出異常,使用limit截取前兩個元素。 6 newMap = list.stream().limit(2).collect(Collectors.toMap(e -> e.substring(0, 1), e -> e)); 7 System.out.println(newMap);// {1=123, 5=521} 8 // 傳入主鍵衝突時的處理方法,保留先插入的值,預設使用HashMap,對主鍵由小到大排序。 9 newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> m)); 10 System.out.println(newMap);// {1=123, 2=228, 3=345, 5=521, 8=838} 11 // 傳入主鍵衝突時的處理方法,保留新插入的值,預設使用LinkedHashMap,對主鍵按照插入順序排序。 12 newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> n, LinkedHashMap::new)); 13 System.out.println(newMap);// {1=100, 5=521, 2=250, 8=838, 3=345} 14 }
joining方法
將流中的元素全部以字元串的方式連接到一起,可以指定連接符,也可以指定前尾碼。
方法:
1 // 將流中的元素全部以字元串的方式連接到一起,不使用連接符,也不指定前尾碼。 2 public static Collector<CharSequence, ?, String> joining() { 3 return new CollectorImpl<CharSequence, StringBuilder, String>( 4 StringBuilder::new, StringBuilder::append, 5 (r1, r2) -> { r1.append(r2); return r1; }, 6 StringBuilder::toString, CH_NOID); 7 } 8 // 將流中的元素全部以字元串的方式連接到一起,使用指定的連接符,不指定前尾碼。 9 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) { 10 return joining(delimiter, "", ""); 11 } 12 // 將流中的元素全部以字元串的方式連接到一起,使用指定的連接符,使用指定的前尾碼。 13 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, 14 CharSequence prefix, 15 CharSequence suffix) { 16 return new CollectorImpl<>( 17 () -> new StringJoiner(delimiter, prefix, suffix), 18 StringJoiner::add, StringJoiner::merge, 19 StringJoiner::toString, CH_NOID); 20 }
實例:
1 public static void main(String[] args) { 2 String str = null; 3 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 4 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 5 str = list.stream().collect(Collectors.joining()); 6 System.out.println(str);// 123521100228838250345 7 str = list.stream().collect(Collectors.joining("-")); 8 System.out.println(str);// 123-521-100-228-838-250-345 9 str = list.stream().collect(Collectors.joining("-", "<", ">")); 10 System.out.println(str);// <123-521-100-228-838-250-345> 11 }
mapping方法
將流中的元素按照傳入的方法進行處理,並將結果按照指定的格式返回。
方法:
1 public static <T, U, A, R> 2 Collector<T, ?, R> mapping( 3 Function<? super T, ? extends U> mapper, 4 Collector<? super U, A, R> downstream) { 5 BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); 6 return new CollectorImpl<>( 7 downstream.supplier(), 8 (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)), 9 downstream.combiner(), 10 downstream.finisher(), 11 downstream.characteristics()); 12 }
實例:
1 public static void main(String[] args) { 2 List<Score> scoreList = new ArrayList<Score>(); 3 scoreList.add(new Score("2019", "10", "張三", 1)); 4 scoreList.add(new Score("2019", "11", "李四", 1)); 5 scoreList.add(new Score("2019", "12", "王五", 1)); 6 List<String> names = scoreList.stream().collect(Collectors.mapping(Score::getName, Collectors.toList())); 7 System.out.println(names);// [張三, 李四, 王五] 8 }
collectingAndThen方法
該方法是按照傳入的collector處理完之後,對歸納的結果進行再處理。
方法:
1 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen( 2 Collector<T,A,R> downstream, 3 Function<R,RR> finisher) { 4 Set<Collector.Characteristics> characteristics = downstream.characteristics(); 5 if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) { 6 if (characteristics.size() == 1) 7 characteristics = Collectors.CH_NOID; 8 else { 9 characteristics = EnumSet.copyOf(characteristics); 10 characteristics.remove(Collector.Characteristics.IDENTITY_FINISH); 11 characteristics = Collections.unmodifiableSet(characteristics); 12 } 13 } 14 return new CollectorImpl<>(downstream.supplier(), 15 downstream.accumulator(), 16 downstream.combiner(), 17 downstream.finisher().andThen(finisher), 18 characteristics); 19 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Integer size = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); 5 System.out.println(size);// 7 6 }
counting方法
該方法主要用來計數。
方法:
1 public static <T> Collector<T, ?, Long> counting() { 2 return reducing(0L, e -> 1L, Long::sum); 3 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Long count = list.stream().collect(Collectors.counting()); 5 System.out.println(count);// 7 6 }
reducing方法
對流中的元素做統計歸納,有三個重載方法,和Stream里的三個reduce方法對應,二者是可以替換使用的,作用完全一致。
方法:
1 // 返回一個可以直接產生Optional類型結果的Collector,沒有初始值。 2 public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) { 3 class OptionalBox implements Consumer<T> { 4 T value = null; 5 boolean present = false; 6 7 @Override 8 public void accept(T t) { 9 if (present) { 10 value = op.apply(value, t); 11 } 12 else { 13 value = t; 14 present = true; 15 } 16 } 17 } 18 return new CollectorImpl<T, OptionalBox, Optional<T>>( 19 OptionalBox::new, OptionalBox::accept, 20 (a, b) -> { if (b.present) a.accept(b.value); return a; }, 21 a -> Optional.ofNullable(a.value), CH_NOID); 22 } 23 // 返回一個可以直接產生結果的Collector,指定初始值。 24 public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) { 25 return new CollectorImpl<>( 26 boxSupplier(identity), 27 (a, t) -> { a[0] = op.apply(a[0], t); }, 28 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 29 a -> a[0], 30 CH_NOID); 31 } 32 // 返回一個可以直接產生結果的Collector,指定初始值,在返回結果之前先使用傳入的方法將流進行轉換。 33 public static <T, U> Collector<T, ?, U> reducing( 34 U identity, 35 Function<? super T, ? extends U> mapper, 36 BinaryOperator<U> op) { 37 return new CollectorImpl<>( 38 boxSupplier(identity), 39 (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); }, 40 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 41 a -> a[0], CH_NOID); 42 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Optional<Integer> optional = list.stream().limit(4).map(String::length).collect(Collectors.reducing(Integer::sum)); 5 System.out.println(optional);// Optional[12] 6 Integer integer = list.stream().limit(3).map(String::length).collect(Collectors.reducing(0, Integer::sum)); 7 System.out.println(integer);// 9 8 Integer sum = list.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum)); 9 System.out.println(sum);// 12 10 }
minBy方法和maxBy方法
生成一個用於獲取最小值或者最大值的Optional結果的Collector。
方法:
1 public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) { 2 return reducing(BinaryOperator.minBy(comparator)); 3 } 4 public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) { 5 return reducing(BinaryOperator.maxBy(comparator)); 6 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Optional<String> max = list.stream().collect(Collectors.maxBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n))); 5 System.out.println(max);// Optional[838] 6 Optional<String> min = list.stream().collect(Collectors.minBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n))); 7 System.out.println(min);// Optional[100] 8 }
summingInt方法、summingLong方法和summingDouble方法
生成一個用於求元素和的Collector,首先將元素轉換類型,然後再求和。
參數的作用就是將元素轉換為指定的類型,最後結果與轉換後類型一致。
方法:
1 public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) { 2 return new CollectorImpl<>( 3 () -> new int[1], 4 (a, t) -> { a[0] += mapper.applyAsInt(t); }, 5 (a, b) -> { a[0] += b[0]; return a; }, 6 a -> a[0], CH_NOID); 7 } 8 public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) { 9 return new CollectorImpl<>( 10 () -> new long[1], 11 (a, t) -> { a[0] += mapper.applyAsLong(t); }, 12 (a, b) -> { a[0] += b[0]; return a; }, 13 a -> a[0], CH_NOID); 14 } 15 public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) { 16 return new CollectorImpl<>( 17 () -> new double[3], 18 (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); 19 a[2] += mapper.applyAsDouble(t); }, 20 (a, b) -> { sumWithCompensation(a, b[0]); 21 a[2] += b[2]; return sumWithCompensation(a, b[1]); }, 22 a -> computeFinalSum(a), CH_NOID); 23 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 Integer intCollect = list.stream().collect(Collectors.summingInt(Integer::parseInt)); 5 System.out.println(intCollect);// 2405 6 Long longCollect = list.stream().collect(Collectors.summingLong(Long::parseLong)); 7 System.out.println(longCollect);// 2405 8 Double doubleCollect = list.stream().collect(Collectors.summingDouble(Double::parseDouble)); 9 System.out.println(doubleCollect);// 2405.0 10 }
summarizingInt方法、summarizingLong方法和summarizingDouble方法
這三個方法適用於彙總的,返回值分別是IntSummaryStatistics、LongSummaryStatistics和DoubleSummaryStatistics。
在這些返回值中包含有流中元素的指定結果的數量、和、最大值、最小值、平均值。
方法:
1 public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) { 2 return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>( 3 IntSummaryStatistics::new, 4 (r, t) -> r.accept(mapper.applyAsInt(t)), 5 (l, r) -> { l.combine(r); return l; }, CH_ID); 6 } 7 public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) { 8 return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>( 9 LongSummaryStatistics::new, 10 (r, t) -> r.accept(mapper.applyAsLong(t)), 11 (l, r) -> { l.combine(r); return l; }, CH_ID); 12 } 13 public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) { 14 return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>( 15 DoubleSummaryStatistics::new, 16 (r, t) -> r.accept(mapper.applyAsDouble(t)), 17 (l, r) -> { l.combine(r); return l; }, CH_ID); 18 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"); 3 System.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 IntSummaryStatistics intSummaryStatistics = list.stream().collect(Collectors.summarizingInt(Integer::parseInt)); 5 System.out.println(intSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838} 6 LongSummaryStatistics longSummaryStatistics = list.stream().collect(Collectors.summarizingLong(Long::parseLong)); 7 System.out.println(longSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838} 8 DoubleSummaryStatistics doubleSummaryStatistics = list.stream().collect(Collectors.summarizingDouble(Double::parseDouble)); 9 System.out.println(doubleSummaryStatistics);// {count=7, sum=2405.000000, min=100.000000, average=343.571429, max=838.000000} 10 }
averagingInt方法、averagingLong方法和averagingDouble方法
生成一個用於求元素平均值的Collector,首先將元素轉換類型,然後再求平均值。
參數的作用就是將元素轉換為指定的類型,求平均值涉及到除法操作,結果一律為Double類型。
方法:
1 public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) { 2 return new CollectorImpl<>( 3 () -> new long[2], 4 (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }, 5 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 6 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); 7 } 8 public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) { 9 return new CollectorImpl<>( 10 () -> new long[2], 11 (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }, 12 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 13 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); 14 } 15 public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) { 16 return new CollectorImpl<>( 17 () -> new double[4], 18 (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t); }, 19 (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, 20 a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID); 21 }
實例:
1 public static void main(String[] args) { 2 List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345"