1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.lang3;
19
20 import java.io.IOException;
21 import java.util.Iterator;
22 import java.util.StringJoiner;
23 import java.util.function.Supplier;
24
25 import org.apache.commons.lang3.exception.UncheckedException;
26 import org.apache.commons.lang3.function.FailableBiConsumer;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 public final class AppendableJoiner<T> {
85
86
87
88
89
90
91 public static final class Builder<T> implements Supplier<AppendableJoiner<T>> {
92
93
94 private CharSequence prefix;
95
96
97 private CharSequence suffix;
98
99
100 private CharSequence delimiter;
101
102
103 private FailableBiConsumer<Appendable, T, IOException> appender;
104
105
106
107
108 Builder() {
109
110 }
111
112
113
114
115 @Override
116 public AppendableJoiner<T> get() {
117 return new AppendableJoiner<>(prefix, suffix, delimiter, appender);
118 }
119
120
121
122
123
124
125
126 public Builder<T> setDelimiter(final CharSequence delimiter) {
127 this.delimiter = delimiter;
128 return this;
129 }
130
131
132
133
134
135
136
137 public Builder<T> setElementAppender(final FailableBiConsumer<Appendable, T, IOException> appender) {
138 this.appender = appender;
139 return this;
140 }
141
142
143
144
145
146
147
148 public Builder<T> setPrefix(final CharSequence prefix) {
149 this.prefix = prefix;
150 return this;
151 }
152
153
154
155
156
157
158
159 public Builder<T> setSuffix(final CharSequence suffix) {
160 this.suffix = suffix;
161 return this;
162 }
163
164 }
165
166
167
168
169
170
171
172 public static <T> Builder<T> builder() {
173 return new Builder<>();
174 }
175
176
177 @SafeVarargs
178 static <A extends Appendable, T> A joinA(final A appendable, final CharSequence prefix, final CharSequence suffix, final CharSequence delimiter,
179 final FailableBiConsumer<Appendable, T, IOException> appender, final T... elements) throws IOException {
180 return joinArray(appendable, prefix, suffix, delimiter, appender, elements);
181 }
182
183 private static <A extends Appendable, T> A joinArray(final A appendable, final CharSequence prefix, final CharSequence suffix, final CharSequence delimiter,
184 final FailableBiConsumer<Appendable, T, IOException> appender, final T[] elements) throws IOException {
185 appendable.append(prefix);
186 if (elements != null) {
187 if (elements.length > 0) {
188 appender.accept(appendable, elements[0]);
189 }
190 for (int i = 1; i < elements.length; i++) {
191 appendable.append(delimiter);
192 appender.accept(appendable, elements[i]);
193 }
194 }
195 appendable.append(suffix);
196 return appendable;
197 }
198
199
200 static <T> StringBuilder joinI(final StringBuilder stringBuilder, final CharSequence prefix, final CharSequence suffix, final CharSequence delimiter,
201 final FailableBiConsumer<Appendable, T, IOException> appender, final Iterable<T> elements) {
202 try {
203 return joinIterable(stringBuilder, prefix, suffix, delimiter, appender, elements);
204 } catch (final IOException e) {
205
206 throw new UncheckedException(e);
207 }
208 }
209
210 private static <A extends Appendable, T> A joinIterable(final A appendable, final CharSequence prefix, final CharSequence suffix,
211 final CharSequence delimiter, final FailableBiConsumer<Appendable, T, IOException> appender, final Iterable<T> elements) throws IOException {
212 appendable.append(prefix);
213 if (elements != null) {
214 final Iterator<T> iterator = elements.iterator();
215 if (iterator.hasNext()) {
216 appender.accept(appendable, iterator.next());
217 }
218 while (iterator.hasNext()) {
219 appendable.append(delimiter);
220 appender.accept(appendable, iterator.next());
221 }
222 }
223 appendable.append(suffix);
224 return appendable;
225 }
226
227
228 @SafeVarargs
229 static <T> StringBuilder joinSB(final StringBuilder stringBuilder, final CharSequence prefix, final CharSequence suffix, final CharSequence delimiter,
230 final FailableBiConsumer<Appendable, T, IOException> appender, final T... elements) {
231 try {
232 return joinArray(stringBuilder, prefix, suffix, delimiter, appender, elements);
233 } catch (final IOException e) {
234
235 throw new UncheckedException(e);
236 }
237 }
238
239 private static CharSequence nonNull(final CharSequence value) {
240 return value != null ? value : StringUtils.EMPTY;
241 }
242
243
244 private final CharSequence prefix;
245
246
247 private final CharSequence suffix;
248
249
250 private final CharSequence delimiter;
251
252 private final FailableBiConsumer<Appendable, T, IOException> appender;
253
254
255
256
257 private AppendableJoiner(final CharSequence prefix, final CharSequence suffix, final CharSequence delimiter,
258 final FailableBiConsumer<Appendable, T, IOException> appender) {
259 this.prefix = nonNull(prefix);
260 this.suffix = nonNull(suffix);
261 this.delimiter = nonNull(delimiter);
262 this.appender = appender != null ? appender : (a, e) -> a.append(String.valueOf(e));
263 }
264
265
266
267
268
269
270
271
272 public StringBuilder join(final StringBuilder stringBuilder, final Iterable<T> elements) {
273 return joinI(stringBuilder, prefix, suffix, delimiter, appender, elements);
274 }
275
276
277
278
279
280
281
282
283 public StringBuilder join(final StringBuilder stringBuilder, @SuppressWarnings("unchecked") final T... elements) {
284 return joinSB(stringBuilder, prefix, suffix, delimiter, appender, elements);
285 }
286
287
288
289
290
291
292
293
294
295
296 public <A extends Appendable> A joinA(final A appendable, final Iterable<T> elements) throws IOException {
297 return joinIterable(appendable, prefix, suffix, delimiter, appender, elements);
298 }
299
300
301
302
303
304
305
306
307
308
309 public <A extends Appendable> A joinA(final A appendable, @SuppressWarnings("unchecked") final T... elements) throws IOException {
310 return joinA(appendable, prefix, suffix, delimiter, appender, elements);
311 }
312
313 }