11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.base;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkNotNull;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.IOException;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.AbstractList;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Arrays;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map.Entry;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.CheckReturnValue;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.Nullable;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * them as a {@link String}. Example: <pre>   {@code
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   Joiner joiner = Joiner.on("; ").skipNulls();
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *    . . .
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   return joiner.join("Harry", null, "Ron", "Hermione");}</pre>
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
430888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * converted to strings using {@link Object#toString()} before being appended.
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * methods will throw {@link NullPointerException} if any given element is null.
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p><b>Warning: joiner instances are always immutable</b>; a configuration method such as {@code
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * static final} constants. <pre>   {@code
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   // Bad! Do not do this!
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   Joiner joiner = Joiner.on(',');
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   joiner.skipNulls(); // does nothing!
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *   return joiner.join("wrong", null, "wrong");}</pre>
580888a09821a98ac0680fad765217302858e70fa4Paul Duffin *
597dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>See the Guava User Guide article on <a href=
600888a09821a98ac0680fad765217302858e70fa4Paul Duffin * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Joiner">{@code Joiner}</a>.
617dd252788645e940eada959bdde927426e2531c9Paul Duffin *
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 2.0 (imported from Google Collections Library)
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class Joiner {
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a joiner which automatically places {@code separator} between consecutive elements.
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public static Joiner on(String separator) {
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new Joiner(separator);
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a joiner which automatically places {@code separator} between consecutive elements.
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public static Joiner on(char separator) {
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new Joiner(String.valueOf(separator));
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private final String separator;
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Joiner(String separator) {
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.separator = checkNotNull(separator);
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Joiner(Joiner prototype) {
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.separator = prototype.separator;
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code appendable}.
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException {
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(appendable, parts.iterator());
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code appendable}.
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @since 11.0
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkNotNull(appendable);
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (parts.hasNext()) {
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      appendable.append(toString(parts.next()));
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (parts.hasNext()) {
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendable.append(separator);
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendable.append(toString(parts.next()));
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendable;
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code appendable}.
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException {
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(appendable, Arrays.asList(parts));
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends to {@code appendable} the string representation of each of the remaining arguments.
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1280888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public final <A extends Appendable> A appendTo(
1290888a09821a98ac0680fad765217302858e70fa4Paul Duffin      A appendable, @Nullable Object first, @Nullable Object second, Object... rest)
1300888a09821a98ac0680fad765217302858e70fa4Paul Duffin          throws IOException {
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(appendable, iterable(first, second, rest));
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Iterable)}, except that it does not throw {@link IOException}.
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(builder, parts.iterator());
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Iterable)}, except that it does not throw {@link IOException}.
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @since 11.0
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      appendTo((Appendable) builder, parts);
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (IOException impossible) {
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new AssertionError(impossible);
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return builder;
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends the string representation of each of {@code parts}, using the previously configured
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Iterable)}, except that it does not throw {@link IOException}.
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final StringBuilder appendTo(StringBuilder builder, Object[] parts) {
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(builder, Arrays.asList(parts));
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Appends to {@code builder} the string representation of each of the remaining arguments.
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * throw {@link IOException}.
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1730888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public final StringBuilder appendTo(
1740888a09821a98ac0680fad765217302858e70fa4Paul Duffin      StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) {
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(builder, iterable(first, second, rest));
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a string containing the string representation of each of {@code parts}, using the
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * previously configured separator between each.
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final String join(Iterable<?> parts) {
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return join(parts.iterator());
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a string containing the string representation of each of {@code parts}, using the
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * previously configured separator between each.
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @since 11.0
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final String join(Iterator<?> parts) {
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return appendTo(new StringBuilder(), parts).toString();
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a string containing the string representation of each of {@code parts}, using the
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * previously configured separator between each.
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final String join(Object[] parts) {
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return join(Arrays.asList(parts));
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a string containing the string representation of each argument, using the previously
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * configured separator between each.
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return join(iterable(first, second, rest));
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a joiner with the same behavior as this one, except automatically substituting {@code
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * nullText} for any provided null elements.
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @CheckReturnValue
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public Joiner useForNull(final String nullText) {
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkNotNull(nullText);
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new Joiner(this) {
2200888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override CharSequence toString(@Nullable Object part) {
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return (part == null) ? nullText : Joiner.this.toString(part);
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2240888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public Joiner useForNull(String nullText) {
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnsupportedOperationException("already specified useForNull");
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2280888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public Joiner skipNulls() {
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnsupportedOperationException("already specified useForNull");
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * provided null elements.
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @CheckReturnValue
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public Joiner skipNulls() {
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new Joiner(this) {
2410888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
2420888a09821a98ac0680fad765217302858e70fa4Paul Duffin          throws IOException {
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        checkNotNull(appendable, "appendable");
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        checkNotNull(parts, "parts");
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        while (parts.hasNext()) {
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          Object part = parts.next();
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (part != null) {
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            appendable.append(Joiner.this.toString(part));
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            break;
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        while (parts.hasNext()) {
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          Object part = parts.next();
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (part != null) {
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            appendable.append(separator);
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            appendable.append(Joiner.this.toString(part));
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return appendable;
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2620888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public Joiner useForNull(String nullText) {
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnsupportedOperationException("already specified skipNulls");
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2660888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public MapJoiner withKeyValueSeparator(String kvs) {
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new UnsupportedOperationException("can't use .skipNulls() with maps");
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * this {@code Joiner} otherwise.
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @CheckReturnValue
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new MapJoiner(this, keyValueSeparator);
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * An object that joins map entries in the same manner as {@code Joiner} joins iterables and
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * arrays. Like {@code Joiner}, it is thread-safe and immutable.
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <p>In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Multimap} entries in two distinct modes:
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <ul>
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <li>To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     {@code MapJoiner} method that accepts entries as input, and receive output of the form
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     {@code key1=A&key1=B&key2=C}.
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * <li>To output a single entry for each key, pass {@code multimap.asMap()} to a {@code MapJoiner}
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     method that accepts a map as input, and receive output of the form {@code
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *     key1=[A, B]&key2=C}.
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * </ul>
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   *
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * @since 2.0 (imported from Google Collections Library)
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2990888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public static final class MapJoiner {
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final Joiner joiner;
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final String keyValueSeparator;
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private MapJoiner(Joiner joiner, String keyValueSeparator) {
3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull
3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.keyValueSeparator = checkNotNull(keyValueSeparator);
3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry of {@code map}, using the previously
3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code appendable}.
3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public <A extends Appendable> A appendTo(A appendable, Map<?, ?> map) throws IOException {
3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendTo(appendable, map.entrySet());
3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry of {@code map}, using the previously
3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code builder}. Identical to {@link
3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}.
3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) {
3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendTo(builder, map.entrySet());
3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Returns a string containing the string representation of each entry of {@code map}, using the
3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * previously configured separator and key-value separator.
3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public String join(Map<?, ?> map) {
3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return join(map.entrySet());
3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry in {@code entries}, using the previously
3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code appendable}.
3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 10.0
3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public <A extends Appendable> A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries)
3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throws IOException {
3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendTo(appendable, entries.iterator());
3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry in {@code entries}, using the previously
3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code appendable}.
3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 11.0
3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throws IOException {
3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkNotNull(appendable);
3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (parts.hasNext()) {
3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Entry<?, ?> entry = parts.next();
3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendable.append(joiner.toString(entry.getKey()));
3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendable.append(keyValueSeparator);
3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendable.append(joiner.toString(entry.getValue()));
3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        while (parts.hasNext()) {
3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          appendable.append(joiner.separator);
3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          Entry<?, ?> e = parts.next();
3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          appendable.append(joiner.toString(e.getKey()));
3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          appendable.append(keyValueSeparator);
3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          appendable.append(joiner.toString(e.getValue()));
3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendable;
3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry in {@code entries}, using the previously
3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code builder}. Identical to {@link
3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 10.0
3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) {
3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendTo(builder, entries.iterator());
3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Appends the string representation of each entry in {@code entries}, using the previously
3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * configured separator and key-value separator, to {@code builder}. Identical to {@link
3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 11.0
3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {
3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        appendTo((Appendable) builder, entries);
3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (IOException impossible) {
3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new AssertionError(impossible);
3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return builder;
3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Returns a string containing the string representation of each entry in {@code entries}, using
4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * the previously configured separator and key-value separator.
4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 10.0
4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public String join(Iterable<? extends Entry<?, ?>> entries) {
4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return join(entries.iterator());
4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Returns a string containing the string representation of each entry in {@code entries}, using
4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * the previously configured separator and key-value separator.
4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     *
4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * @since 11.0
4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Beta
4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public String join(Iterator<? extends Entry<?, ?>> entries) {
4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return appendTo(new StringBuilder(), entries).toString();
4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Returns a map joiner with the same behavior as this one, except automatically substituting
4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * {@code nullText} for any provided null keys or values.
4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @CheckReturnValue
4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public MapJoiner useForNull(String nullText) {
4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator);
4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  CharSequence toString(Object part) {
4330888a09821a98ac0680fad765217302858e70fa4Paul Duffin    checkNotNull(part);  // checkNotNull for GWT (do not optimize).
4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4370888a09821a98ac0680fad765217302858e70fa4Paul Duffin  private static Iterable<Object> iterable(
4380888a09821a98ac0680fad765217302858e70fa4Paul Duffin      final Object first, final Object second, final Object[] rest) {
4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkNotNull(rest);
4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new AbstractList<Object>() {
4410888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public int size() {
4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return rest.length + 2;
4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4450888a09821a98ac0680fad765217302858e70fa4Paul Duffin      @Override public Object get(int index) {
4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        switch (index) {
4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          case 0:
4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return first;
4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          case 1:
4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return second;
4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          default:
4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return rest[index - 2];
4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
458