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