javadoc.src-html.com.google.common.base.Joiner.html Maven / Gradle / Ivy
The newest version!
001 /*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.base;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022 import com.google.common.annotations.GwtCompatible;
023
024 import java.io.IOException;
025 import java.util.AbstractList;
026 import java.util.Arrays;
027 import java.util.Iterator;
028 import java.util.Map;
029 import java.util.Map.Entry;
030
031 import javax.annotation.CheckReturnValue;
032 import javax.annotation.Nullable;
033
034 /**
035 * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a
036 * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns
037 * them as a {@link String}. Example: <pre> {@code
038 *
039 * Joiner joiner = Joiner.on("; ").skipNulls();
040 * . . .
041 * return joiner.join("Harry", null, "Ron", "Hermione");}</pre>
042 *
043 * This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are
044 * converted to strings using {@link Object#toString()} before being appended.
045 *
046 * <p>If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining
047 * methods will throw {@link NullPointerException} if any given element is null.
048 *
049 * <p><b>Warning: joiner instances are always immutable</b>; a configuration method such as {@code
050 * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner
051 * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code
052 * static final} constants. <pre> {@code
053 *
054 * // Bad! Do not do this!
055 * Joiner joiner = Joiner.on(',');
056 * joiner.skipNulls(); // does nothing!
057 * return joiner.join("wrong", null, "wrong");}</pre>
058 *
059 * @author Kevin Bourrillion
060 * @since 2.0 (imported from Google Collections Library)
061 */
062 @GwtCompatible
063 public class Joiner {
064 /**
065 * Returns a joiner which automatically places {@code separator} between consecutive elements.
066 */
067 public static Joiner on(String separator) {
068 return new Joiner(separator);
069 }
070
071 /**
072 * Returns a joiner which automatically places {@code separator} between consecutive elements.
073 */
074 public static Joiner on(char separator) {
075 return new Joiner(String.valueOf(separator));
076 }
077
078 private final String separator;
079
080 private Joiner(String separator) {
081 this.separator = checkNotNull(separator);
082 }
083
084 private Joiner(Joiner prototype) {
085 this.separator = prototype.separator;
086 }
087
088 /**
089 * <b>Deprecated.</b>
090 *
091 * @since 11.0
092 * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code parts} to
093 * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
094 * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
095 */
096 @Beta
097 @Deprecated
098 public final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A
099 appendTo(A appendable, I parts) throws IOException {
100 return appendTo(appendable, (Iterator<?>) parts);
101 }
102
103 /**
104 * Appends the string representation of each of {@code parts}, using the previously configured
105 * separator between each, to {@code appendable}.
106 */
107 public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException {
108 return appendTo(appendable, parts.iterator());
109 }
110
111 /**
112 * Appends the string representation of each of {@code parts}, using the previously configured
113 * separator between each, to {@code appendable}.
114 *
115 * @since 11.0
116 */
117 @Beta
118 public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
119 checkNotNull(appendable);
120 if (parts.hasNext()) {
121 appendable.append(toString(parts.next()));
122 while (parts.hasNext()) {
123 appendable.append(separator);
124 appendable.append(toString(parts.next()));
125 }
126 }
127 return appendable;
128 }
129
130 /**
131 * Appends the string representation of each of {@code parts}, using the previously configured
132 * separator between each, to {@code appendable}.
133 */
134 public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException {
135 return appendTo(appendable, Arrays.asList(parts));
136 }
137
138 /**
139 * Appends to {@code appendable} the string representation of each of the remaining arguments.
140 */
141 public final <A extends Appendable> A appendTo(
142 A appendable, @Nullable Object first, @Nullable Object second, Object... rest)
143 throws IOException {
144 return appendTo(appendable, iterable(first, second, rest));
145 }
146
147 /**
148 * <b>Deprecated.</b>
149 *
150 * @since 11.0
151 * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code parts} to
152 * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
153 * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
154 */
155 @Beta
156 @Deprecated
157 public final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder
158 appendTo(StringBuilder builder, I parts) {
159 return appendTo(builder, (Iterator<?>) parts);
160 }
161
162 /**
163 * Appends the string representation of each of {@code parts}, using the previously configured
164 * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
165 * Iterable)}, except that it does not throw {@link IOException}.
166 */
167 public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
168 return appendTo(builder, parts.iterator());
169 }
170
171 /**
172 * Appends the string representation of each of {@code parts}, using the previously configured
173 * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
174 * Iterable)}, except that it does not throw {@link IOException}.
175 *
176 * @since 11.0
177 */
178 @Beta
179 public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
180 try {
181 appendTo((Appendable) builder, parts);
182 } catch (IOException impossible) {
183 throw new AssertionError(impossible);
184 }
185 return builder;
186 }
187
188 /**
189 * Appends the string representation of each of {@code parts}, using the previously configured
190 * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
191 * Iterable)}, except that it does not throw {@link IOException}.
192 */
193 public final StringBuilder appendTo(StringBuilder builder, Object[] parts) {
194 return appendTo(builder, Arrays.asList(parts));
195 }
196
197 /**
198 * Appends to {@code builder} the string representation of each of the remaining arguments.
199 * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
200 * throw {@link IOException}.
201 */
202 public final StringBuilder appendTo(
203 StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) {
204 return appendTo(builder, iterable(first, second, rest));
205 }
206
207 /**
208 * <b>Deprecated.</b>
209 *
210 * @since 11.0
211 * @deprecated use {@link #join(Iterator)} by casting {@code parts} to
212 * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
213 * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
214 */
215 @Beta
216 @Deprecated
217 public final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) {
218 return join((Iterator<?>) parts);
219 }
220
221 /**
222 * Returns a string containing the string representation of each of {@code parts}, using the
223 * previously configured separator between each.
224 */
225 public final String join(Iterable<?> parts) {
226 return join(parts.iterator());
227 }
228
229 /**
230 * Returns a string containing the string representation of each of {@code parts}, using the
231 * previously configured separator between each.
232 *
233 * @since 11.0
234 */
235 @Beta
236 public final String join(Iterator<?> parts) {
237 return appendTo(new StringBuilder(), parts).toString();
238 }
239
240 /**
241 * Returns a string containing the string representation of each of {@code parts}, using the
242 * previously configured separator between each.
243 */
244 public final String join(Object[] parts) {
245 return join(Arrays.asList(parts));
246 }
247
248 /**
249 * Returns a string containing the string representation of each argument, using the previously
250 * configured separator between each.
251 */
252 public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
253 return join(iterable(first, second, rest));
254 }
255
256 /**
257 * Returns a joiner with the same behavior as this one, except automatically substituting {@code
258 * nullText} for any provided null elements.
259 */
260 @CheckReturnValue
261 public Joiner useForNull(final String nullText) {
262 checkNotNull(nullText);
263 return new Joiner(this) {
264 @Override CharSequence toString(Object part) {
265 return (part == null) ? nullText : Joiner.this.toString(part);
266 }
267
268 @Override public Joiner useForNull(String nullText) {
269 checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
270 throw new UnsupportedOperationException("already specified useForNull");
271 }
272
273 @Override public Joiner skipNulls() {
274 throw new UnsupportedOperationException("already specified useForNull");
275 }
276 };
277 }
278
279 /**
280 * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
281 * provided null elements.
282 */
283 @CheckReturnValue
284 public Joiner skipNulls() {
285 return new Joiner(this) {
286 @Override public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
287 throws IOException {
288 checkNotNull(appendable, "appendable");
289 checkNotNull(parts, "parts");
290 while (parts.hasNext()) {
291 Object part = parts.next();
292 if (part != null) {
293 appendable.append(Joiner.this.toString(part));
294 break;
295 }
296 }
297 while (parts.hasNext()) {
298 Object part = parts.next();
299 if (part != null) {
300 appendable.append(separator);
301 appendable.append(Joiner.this.toString(part));
302 }
303 }
304 return appendable;
305 }
306
307 @Override public Joiner useForNull(String nullText) {
308 checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
309 throw new UnsupportedOperationException("already specified skipNulls");
310 }
311
312 @Override public MapJoiner withKeyValueSeparator(String kvs) {
313 checkNotNull(kvs); // weird: just to satisfy NullPointerTester.
314 throw new UnsupportedOperationException("can't use .skipNulls() with maps");
315 }
316 };
317 }
318
319 /**
320 * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
321 * this {@code Joiner} otherwise.
322 */
323 @CheckReturnValue
324 public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
325 return new MapJoiner(this, keyValueSeparator);
326 }
327
328 /**
329 * An object that joins map entries in the same manner as {@code Joiner} joins iterables and
330 * arrays. Like {@code Joiner}, it is thread-safe and immutable.
331 *
332 * <p>In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code
333 * Multimap} entries in two distinct modes:
334 *
335 * <ul>
336 * <li>To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a
337 * {@code MapJoiner} method that accepts entries as input, and receive output of the form
338 * {@code key1=A&key1=B&key2=C}.
339 * <li>To output a single entry for each key, pass {@code multimap.asMap()} to a {@code MapJoiner}
340 * method that accepts a map as input, and receive output of the form {@code
341 * key1=[A, B]&key2=C}.
342 * </ul>
343 *
344 * @since 2.0 (imported from Google Collections Library)
345 */
346 public final static class MapJoiner {
347 private final Joiner joiner;
348 private final String keyValueSeparator;
349
350 private MapJoiner(Joiner joiner, String keyValueSeparator) {
351 this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull
352 this.keyValueSeparator = checkNotNull(keyValueSeparator);
353 }
354
355 /**
356 * Appends the string representation of each entry of {@code map}, using the previously
357 * configured separator and key-value separator, to {@code appendable}.
358 */
359 public <A extends Appendable> A appendTo(A appendable, Map<?, ?> map) throws IOException {
360 return appendTo(appendable, map.entrySet());
361 }
362
363 /**
364 * Appends the string representation of each entry of {@code map}, using the previously
365 * configured separator and key-value separator, to {@code builder}. Identical to {@link
366 * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}.
367 */
368 public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) {
369 return appendTo(builder, map.entrySet());
370 }
371
372 /**
373 * Returns a string containing the string representation of each entry of {@code map}, using the
374 * previously configured separator and key-value separator.
375 */
376 public String join(Map<?, ?> map) {
377 return join(map.entrySet());
378 }
379
380 /**
381 * <b>Deprecated.</b>
382 *
383 * @since 11.0
384 * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code entries} to
385 * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
386 * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
387 * in June 2013.</b>
388 */
389 @Beta
390 @Deprecated
391 public <A extends Appendable,
392 I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
393 A appendTo(A appendable, I entries) throws IOException {
394 Iterator<? extends Entry<?, ?>> iterator = entries;
395 return appendTo(appendable, iterator);
396 }
397
398 /**
399 * Appends the string representation of each entry in {@code entries}, using the previously
400 * configured separator and key-value separator, to {@code appendable}.
401 *
402 * @since 10.0
403 */
404 @Beta
405 public <A extends Appendable> A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries)
406 throws IOException {
407 return appendTo(appendable, entries.iterator());
408 }
409
410 /**
411 * Appends the string representation of each entry in {@code entries}, using the previously
412 * configured separator and key-value separator, to {@code appendable}.
413 *
414 * @since 11.0
415 */
416 @Beta
417 public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
418 throws IOException {
419 checkNotNull(appendable);
420 if (parts.hasNext()) {
421 Entry<?, ?> entry = parts.next();
422 appendable.append(joiner.toString(entry.getKey()));
423 appendable.append(keyValueSeparator);
424 appendable.append(joiner.toString(entry.getValue()));
425 while (parts.hasNext()) {
426 appendable.append(joiner.separator);
427 Entry<?, ?> e = parts.next();
428 appendable.append(joiner.toString(e.getKey()));
429 appendable.append(keyValueSeparator);
430 appendable.append(joiner.toString(e.getValue()));
431 }
432 }
433 return appendable;
434 }
435
436 /**
437 * <b>Deprecated.</b>
438 *
439 * @since 11.0
440 * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code entries} to
441 * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
442 * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
443 * in June 2013.</b>
444 */
445 @Beta
446 @Deprecated
447 public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
448 StringBuilder appendTo(StringBuilder builder, I entries) throws IOException {
449 Iterator<? extends Entry<?, ?>> iterator = entries;
450 return appendTo(builder, iterator);
451 }
452
453 /**
454 * Appends the string representation of each entry in {@code entries}, using the previously
455 * configured separator and key-value separator, to {@code builder}. Identical to {@link
456 * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
457 *
458 * @since 10.0
459 */
460 @Beta
461 public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) {
462 return appendTo(builder, entries.iterator());
463 }
464
465 /**
466 * Appends the string representation of each entry in {@code entries}, using the previously
467 * configured separator and key-value separator, to {@code builder}. Identical to {@link
468 * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
469 *
470 * @since 11.0
471 */
472 @Beta
473 public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {
474 try {
475 appendTo((Appendable) builder, entries);
476 } catch (IOException impossible) {
477 throw new AssertionError(impossible);
478 }
479 return builder;
480 }
481
482 /**
483 * <b>Deprecated.</b>
484 *
485 * @since 11.0
486 * @deprecated use {@link #join(Iterator)} by casting {@code entries} to
487 * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
488 * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
489 * in June 2013.</b>
490 */
491 @Beta
492 @Deprecated
493 public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
494 String join(I entries) throws IOException {
495 Iterator<? extends Entry<?, ?>> iterator = entries;
496 return join(iterator);
497 }
498
499 /**
500 * Returns a string containing the string representation of each entry in {@code entries}, using
501 * the previously configured separator and key-value separator.
502 *
503 * @since 10.0
504 */
505 @Beta
506 public String join(Iterable<? extends Entry<?, ?>> entries) {
507 return join(entries.iterator());
508 }
509
510 /**
511 * Returns a string containing the string representation of each entry in {@code entries}, using
512 * the previously configured separator and key-value separator.
513 *
514 * @since 11.0
515 */
516 @Beta
517 public String join(Iterator<? extends Entry<?, ?>> entries) {
518 return appendTo(new StringBuilder(), entries).toString();
519 }
520
521 /**
522 * Returns a map joiner with the same behavior as this one, except automatically substituting
523 * {@code nullText} for any provided null keys or values.
524 */
525 @CheckReturnValue
526 public MapJoiner useForNull(String nullText) {
527 return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator);
528 }
529 }
530
531 CharSequence toString(Object part) {
532 checkNotNull(part); // checkNotNull for GWT (do not optimize).
533 return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
534 }
535
536 private static Iterable<Object> iterable(
537 final Object first, final Object second, final Object[] rest) {
538 checkNotNull(rest);
539 return new AbstractList<Object>() {
540 @Override public int size() {
541 return rest.length + 2;
542 }
543
544 @Override public Object get(int index) {
545 switch (index) {
546 case 0:
547 return first;
548 case 1:
549 return second;
550 default:
551 return rest[index - 2];
552 }
553 }
554 };
555 }
556 }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy