JDK1.8新特性——Collector介面和Collectors工具類

来源:https://www.cnblogs.com/shamao/archive/2019/11/09/11828204.html
-Advertisement-
Play Games

本文主要學習了在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"	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、概述二、Struts2 快速入門程式2.1 開發流程比較2.2 引入依賴2.2 創建jsp頁面2.3 在web.xml中配置前端控制器2.4 創建struts.xml配置文件2.4 創建一個HelloAction類2.5 在struts.xml文件中配置HelloAction2.6 在index... ...
  • 手寫SpringMVC框架 細嗅薔薇 心有猛虎 背景:Spring 想必大家都聽說過,可能現在更多流行的是Spring Boot 和Spring Cloud 框架;但是SpringMVC 作為一款實現了MVC 設計模式的web (表現層) 層框架,其高開發效率和高性能也是現在很多公司仍在採用的框架; ...
  • 概述 今天給大家分享,在 API 端使用 Gin 框架時,項目的目錄。目錄 ├─ Project Name │ ├─ config //配置文件 │ ├── ... │ ├─ controller //控制器層 │ ├── ... │ ├─ service //業務層 │ ├── ... │ ├─ ...
  • 一、re舉例 import re #查找數字 p = re.compile(r"\d+") #在字元串“ongahjeuf125”中及逆行查找,按照規則p指定的正則進行查找 m = p.match("ong125fdsgdsf48515",3,20)#後面的參數序號3到6的搜索範圍 print(m) ...
  • 1. 引入工程依賴包 2. 編寫DAO介面 3. 編寫SQL配置文件(本人不太習慣註解,習慣將SQL寫在配置文件中) 4. 配置myBatis配置類,也可以放在啟動類上 5. 配置application.yml文件 6. 編寫controller,調用MyBatis 源代碼: "https://gi ...
  • 概述首先同步下項目概況:上篇文章分享了,使用 go modules 初始化項目,這篇文章咱們分享: 規劃目錄結構 模型綁定和驗證 自定義驗證器 制定 API 返回結構廢話不多說,咱們開始吧。規劃目錄結構 ├─ go-gin-api │ ├─ app │ ├─ config //配置文件 │ ├─ c ...
  • 一、關於Quartz Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,它可以與J2EE與J2SE應用程式相結合也可以單獨使用。在java企業級應用中,Quartz是使用最廣泛的定時調度框架。 在Quartz中的主要概念: Scheduler:調度任務的 ...
  • 概述首先同步下項目概況:上篇文章分享了,規劃項目目錄和參數驗證,其中參數驗證使用的是 validator.v8 版本,現已更新到 validator.v9 版本,最新代碼查看 github 即可。這篇文章咱們分享:路由中間件 - 日誌記錄。日誌是特別重要的一個東西,方便我們對問題進行排查,這篇文章我 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...