View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.lang3.stream;
19  
20  import java.util.Collections;
21  import java.util.Objects;
22  import java.util.Set;
23  import java.util.StringJoiner;
24  import java.util.function.BiConsumer;
25  import java.util.function.BinaryOperator;
26  import java.util.function.Function;
27  import java.util.function.Supplier;
28  import java.util.stream.Collector;
29  import java.util.stream.Collectors;
30  
31  import org.apache.commons.lang3.StringUtils;
32  
33  /**
34   * Implementations of {@link Collector} that implement various useful reduction operations.
35   * <p>
36   * This class is called {@code LangCollectors} instead of {@code Collectors} to avoid clashes with {@link Collectors}.
37   * </p>
38   *
39   * @since 3.13.0
40   */
41  public final class LangCollectors {
42  
43      /**
44       * Simple implementation class for {@code Collector}.
45       *
46       * @param <T> the type of elements to be collected
47       * @param <R> the type of the result
48       */
49      private static final class SimpleCollector<T, A, R> implements Collector<T, A, R> {
50  
51          private final BiConsumer<A, T> accumulator;
52          private final Set<Characteristics> characteristics;
53          private final BinaryOperator<A> combiner;
54          private final Function<A, R> finisher;
55          private final Supplier<A> supplier;
56  
57          private SimpleCollector(final Supplier<A> supplier, final BiConsumer<A, T> accumulator, final BinaryOperator<A> combiner, final Function<A, R> finisher,
58              final Set<Characteristics> characteristics) {
59              this.supplier = supplier;
60              this.accumulator = accumulator;
61              this.combiner = combiner;
62              this.finisher = finisher;
63              this.characteristics = characteristics;
64          }
65  
66          @Override
67          public BiConsumer<A, T> accumulator() {
68              return accumulator;
69          }
70  
71          @Override
72          public Set<Characteristics> characteristics() {
73              return characteristics;
74          }
75  
76          @Override
77          public BinaryOperator<A> combiner() {
78              return combiner;
79          }
80  
81          @Override
82          public Function<A, R> finisher() {
83              return finisher;
84          }
85  
86          @Override
87          public Supplier<A> supplier() {
88              return supplier;
89          }
90      }
91  
92      private static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
93  
94      /**
95       * Returns a {@code Collector} that concatenates the input elements, separated by the specified delimiter, in encounter
96       * order.
97       * <p>
98       * This is a variation of {@link Collectors#joining()} that works with any element class, not just {@code CharSequence}.
99       * </p>
100      *
101      * @return A {@code Collector} which concatenates Object elements, separated by the specified delimiter, in encounter
102      *         order.
103      */
104     public static Collector<Object, ?, String> joining() {
105         return new SimpleCollector<>(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString, CH_NOID);
106     }
107 
108     /**
109      * Returns a {@code Collector} that concatenates the input elements, separated by the specified delimiter, in encounter
110      * order.
111      * <p>
112      * This is a variation of {@link Collectors#joining(CharSequence)} that works with any element class, not just
113      * {@code CharSequence}.
114      * </p>
115      *
116      * @param delimiter the delimiter to be used between each element.
117      * @return A {@code Collector} which concatenates Object elements, separated by the specified delimiter, in encounter
118      *         order.
119      */
120     public static Collector<Object, ?, String> joining(final CharSequence delimiter) {
121         return joining(delimiter, StringUtils.EMPTY, StringUtils.EMPTY);
122     }
123 
124     /**
125      * Returns a {@code Collector} that concatenates the input elements, separated by the specified delimiter, with the
126      * specified prefix and suffix, in encounter order.
127      * <p>
128      * This is a variation of {@link Collectors#joining(CharSequence, CharSequence, CharSequence)} that works with any
129      * element class, not just {@code CharSequence}.
130      * </p>
131      *
132      * @param delimiter the delimiter to be used between each element
133      * @param prefix the sequence of characters to be used at the beginning of the joined result
134      * @param suffix the sequence of characters to be used at the end of the joined result
135      * @return A {@code Collector} which concatenates CharSequence elements, separated by the specified delimiter, in
136      *         encounter order
137      */
138     public static Collector<Object, ?, String> joining(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix) {
139         return joining(delimiter, prefix, suffix, Objects::toString);
140     }
141 
142     /**
143      * Returns a {@code Collector} that concatenates the input elements, separated by the specified delimiter, with the
144      * specified prefix and suffix, in encounter order.
145      * <p>
146      * This is a variation of {@link Collectors#joining(CharSequence, CharSequence, CharSequence)} that works with any
147      * element class, not just {@code CharSequence}.
148      * </p>
149      *
150      * @param delimiter the delimiter to be used between each element
151      * @param prefix the sequence of characters to be used at the beginning of the joined result
152      * @param suffix the sequence of characters to be used at the end of the joined result
153      * @param toString A function that takes an Object and returns a non-null String.
154      * @return A {@code Collector} which concatenates CharSequence elements, separated by the specified delimiter, in
155      *         encounter order
156      */
157     public static Collector<Object, ?, String> joining(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix,
158         final Function<Object, String> toString) {
159         return new SimpleCollector<>(() -> new StringJoiner(delimiter, prefix, suffix), (a, t) -> a.add(toString.apply(t)), StringJoiner::merge,
160             StringJoiner::toString, CH_NOID);
161     }
162 
163     private LangCollectors() {
164         // No instance
165     }
166 
167 }