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 }