blob: b6ba84c5df8a58668787ee0614cee8095d1b4d17 [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package java.util;
26
27/**
28 * {@code StringJoiner} is used to construct a sequence of characters separated
29 * by a delimiter and optionally starting with a supplied prefix
30 * and ending with a supplied suffix.
31 * <p>
32 * Prior to adding something to the {@code StringJoiner}, its
33 * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
34 * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
35 * supplied will be returned instead. This can be used, for example, when
36 * creating a string using set notation to indicate an empty set, i.e.
37 * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
38 * {@code suffix} is <code>"}"</code> and nothing has been added to the
39 * {@code StringJoiner}.
40 *
41 * @apiNote
42 * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
43 *
44 * <pre> {@code
45 * StringJoiner sj = new StringJoiner(":", "[", "]");
46 * sj.add("George").add("Sally").add("Fred");
47 * String desiredString = sj.toString();
48 * }</pre>
49 * <p>
50 * A {@code StringJoiner} may be employed to create formatted output from a
51 * {@link java.util.stream.Stream} using
52 * {@link java.util.stream.Collectors#joining(CharSequence)}. For example:
53 *
54 * <pre> {@code
55 * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
56 * String commaSeparatedNumbers = numbers.stream()
57 * .map(i -> i.toString())
58 * .collect(Collectors.joining(", "));
59 * }</pre>
60 *
61 * @see java.util.stream.Collectors#joining(CharSequence)
62 * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
63 * @since 1.8
64*/
65public final class StringJoiner {
66 private final String prefix;
67 private final String delimiter;
68 private final String suffix;
69
70 /*
71 * StringBuilder value -- at any time, the characters constructed from the
72 * prefix, the added element separated by the delimiter, but without the
73 * suffix, so that we can more easily add elements without having to jigger
74 * the suffix each time.
75 */
76 private StringBuilder value;
77
78 /*
79 * By default, the string consisting of prefix+suffix, returned by
80 * toString(), or properties of value, when no elements have yet been added,
81 * i.e. when it is empty. This may be overridden by the user to be some
82 * other value including the empty String.
83 */
84 private String emptyValue;
85
86 /**
87 * Constructs a {@code StringJoiner} with no characters in it, with no
88 * {@code prefix} or {@code suffix}, and a copy of the supplied
89 * {@code delimiter}.
90 * If no characters are added to the {@code StringJoiner} and methods
91 * accessing the value of it are invoked, it will not return a
92 * {@code prefix} or {@code suffix} (or properties thereof) in the result,
93 * unless {@code setEmptyValue} has first been called.
94 *
95 * @param delimiter the sequence of characters to be used between each
96 * element added to the {@code StringJoiner} value
97 * @throws NullPointerException if {@code delimiter} is {@code null}
98 */
99 public StringJoiner(CharSequence delimiter) {
100 this(delimiter, "", "");
101 }
102
103 /**
104 * Constructs a {@code StringJoiner} with no characters in it using copies
105 * of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
106 * If no characters are added to the {@code StringJoiner} and methods
107 * accessing the string value of it are invoked, it will return the
108 * {@code prefix + suffix} (or properties thereof) in the result, unless
109 * {@code setEmptyValue} has first been called.
110 *
111 * @param delimiter the sequence of characters to be used between each
112 * element added to the {@code StringJoiner}
113 * @param prefix the sequence of characters to be used at the beginning
114 * @param suffix the sequence of characters to be used at the end
115 * @throws NullPointerException if {@code prefix}, {@code delimiter}, or
116 * {@code suffix} is {@code null}
117 */
118 public StringJoiner(CharSequence delimiter,
119 CharSequence prefix,
120 CharSequence suffix) {
121 Objects.requireNonNull(prefix, "The prefix must not be null");
122 Objects.requireNonNull(delimiter, "The delimiter must not be null");
123 Objects.requireNonNull(suffix, "The suffix must not be null");
124 // make defensive copies of arguments
125 this.prefix = prefix.toString();
126 this.delimiter = delimiter.toString();
127 this.suffix = suffix.toString();
128 this.emptyValue = this.prefix + this.suffix;
129 }
130
131 /**
132 * Sets the sequence of characters to be used when determining the string
133 * representation of this {@code StringJoiner} and no elements have been
134 * added yet, that is, when it is empty. A copy of the {@code emptyValue}
135 * parameter is made for this purpose. Note that once an add method has been
136 * called, the {@code StringJoiner} is no longer considered empty, even if
137 * the element(s) added correspond to the empty {@code String}.
138 *
139 * @param emptyValue the characters to return as the value of an empty
140 * {@code StringJoiner}
141 * @return this {@code StringJoiner} itself so the calls may be chained
142 * @throws NullPointerException when the {@code emptyValue} parameter is
143 * {@code null}
144 */
145 public StringJoiner setEmptyValue(CharSequence emptyValue) {
146 this.emptyValue = Objects.requireNonNull(emptyValue,
147 "The empty value must not be null").toString();
148 return this;
149 }
150
151 /**
152 * Returns the current value, consisting of the {@code prefix}, the values
153 * added so far separated by the {@code delimiter}, and the {@code suffix},
154 * unless no elements have been added in which case, the
155 * {@code prefix + suffix} or the {@code emptyValue} characters are returned
156 *
157 * @return the string representation of this {@code StringJoiner}
158 */
159 @Override
160 public String toString() {
161 if (value == null) {
162 return emptyValue;
163 } else {
164 if (suffix.equals("")) {
165 return value.toString();
166 } else {
167 int initialLength = value.length();
168 String result = value.append(suffix).toString();
169 // reset value to pre-append initialLength
170 value.setLength(initialLength);
171 return result;
172 }
173 }
174 }
175
176 /**
177 * Adds a copy of the given {@code CharSequence} value as the next
178 * element of the {@code StringJoiner} value. If {@code newElement} is
179 * {@code null}, then {@code "null"} is added.
180 *
181 * @param newElement The element to add
182 * @return a reference to this {@code StringJoiner}
183 */
184 public StringJoiner add(CharSequence newElement) {
185 prepareBuilder().append(newElement);
186 return this;
187 }
188
189 /**
190 * Adds the contents of the given {@code StringJoiner} without prefix and
191 * suffix as the next element if it is non-empty. If the given {@code
192 * StringJoiner} is empty, the call has no effect.
193 *
194 * <p>A {@code StringJoiner} is empty if {@link #add(CharSequence) add()}
195 * has never been called, and if {@code merge()} has never been called
196 * with a non-empty {@code StringJoiner} argument.
197 *
198 * <p>If the other {@code StringJoiner} is using a different delimiter,
199 * then elements from the other {@code StringJoiner} are concatenated with
200 * that delimiter and the result is appended to this {@code StringJoiner}
201 * as a single element.
202 *
203 * @param other The {@code StringJoiner} whose contents should be merged
204 * into this one
205 * @throws NullPointerException if the other {@code StringJoiner} is null
206 * @return This {@code StringJoiner}
207 */
208 public StringJoiner merge(StringJoiner other) {
209 Objects.requireNonNull(other);
210 if (other.value != null) {
211 final int length = other.value.length();
212 // lock the length so that we can seize the data to be appended
213 // before initiate copying to avoid interference, especially when
214 // merge 'this'
215 StringBuilder builder = prepareBuilder();
216 builder.append(other.value, other.prefix.length(), length);
217 }
218 return this;
219 }
220
221 private StringBuilder prepareBuilder() {
222 if (value != null) {
223 value.append(delimiter);
224 } else {
225 value = new StringBuilder().append(prefix);
226 }
227 return value;
228 }
229
230 /**
231 * Returns the length of the {@code String} representation
232 * of this {@code StringJoiner}. Note that if
233 * no add methods have been called, then the length of the {@code String}
234 * representation (either {@code prefix + suffix} or {@code emptyValue})
235 * will be returned. The value should be equivalent to
236 * {@code toString().length()}.
237 *
238 * @return the length of the current value of {@code StringJoiner}
239 */
240 public int length() {
241 // Remember that we never actually append the suffix unless we return
242 // the full (present) value or some sub-string or length of it, so that
243 // we can add on more if we need to.
244 return (value != null ? value.length() + suffix.length() :
245 emptyValue.length());
246 }
247}