1 /*
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 */
25 package 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");
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 */
65 public 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}.
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 }
|
1 /*
2 * Copyright (c) 2013, 2014, 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 */
25 package java.util;
26
27 import sun.misc.JavaLangAccess;
28 import sun.misc.SharedSecrets;
29
30 /**
31 * {@code StringJoiner} is used to construct a sequence of characters separated
32 * by a delimiter and optionally starting with a supplied prefix
33 * and ending with a supplied suffix.
34 * <p>
35 * Prior to adding something to the {@code StringJoiner}, its
36 * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
37 * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
38 * supplied will be returned instead. This can be used, for example, when
39 * creating a string using set notation to indicate an empty set, i.e.
40 * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
41 * {@code suffix} is <code>"}"</code> and nothing has been added to the
42 * {@code StringJoiner}.
43 *
44 * @apiNote
45 * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
46 *
47 * <pre> {@code
48 * StringJoiner sj = new StringJoiner(":", "[", "]");
49 * sj.add("George").add("Sally").add("Fred");
53 * A {@code StringJoiner} may be employed to create formatted output from a
54 * {@link java.util.stream.Stream} using
55 * {@link java.util.stream.Collectors#joining(CharSequence)}. For example:
56 *
57 * <pre> {@code
58 * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
59 * String commaSeparatedNumbers = numbers.stream()
60 * .map(i -> i.toString())
61 * .collect(Collectors.joining(", "));
62 * }</pre>
63 *
64 * @see java.util.stream.Collectors#joining(CharSequence)
65 * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
66 * @since 1.8
67 */
68 public final class StringJoiner {
69 private final String prefix;
70 private final String delimiter;
71 private final String suffix;
72
73 /** Contains all the string components added so far. */
74 private String[] elts;
75
76 /** The number of string components added so far. */
77 private int size;
78
79 /** Total length in chars so far, excluding prefix and suffix. */
80 private int len;
81
82 /**
83 * When overriden by the user to be non-null via {@link setEmptyValue}, the
84 * string returned by toString() when no elements have yet been added.
85 * When null, prefix + suffix is used as the empty value.
86 */
87 private String emptyValue;
88
89 private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
90
91 /**
92 * Constructs a {@code StringJoiner} with no characters in it, with no
93 * {@code prefix} or {@code suffix}, and a copy of the supplied
94 * {@code delimiter}.
95 * If no characters are added to the {@code StringJoiner} and methods
96 * accessing the value of it are invoked, it will not return a
97 * {@code prefix} or {@code suffix} (or properties thereof) in the result,
98 * unless {@code setEmptyValue} has first been called.
99 *
100 * @param delimiter the sequence of characters to be used between each
101 * element added to the {@code StringJoiner} value
102 * @throws NullPointerException if {@code delimiter} is {@code null}
103 */
104 public StringJoiner(CharSequence delimiter) {
105 this(delimiter, "", "");
106 }
107
108 /**
109 * Constructs a {@code StringJoiner} with no characters in it using copies
110 * of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
113 * {@code prefix + suffix} (or properties thereof) in the result, unless
114 * {@code setEmptyValue} has first been called.
115 *
116 * @param delimiter the sequence of characters to be used between each
117 * element added to the {@code StringJoiner}
118 * @param prefix the sequence of characters to be used at the beginning
119 * @param suffix the sequence of characters to be used at the end
120 * @throws NullPointerException if {@code prefix}, {@code delimiter}, or
121 * {@code suffix} is {@code null}
122 */
123 public StringJoiner(CharSequence delimiter,
124 CharSequence prefix,
125 CharSequence suffix) {
126 Objects.requireNonNull(prefix, "The prefix must not be null");
127 Objects.requireNonNull(delimiter, "The delimiter must not be null");
128 Objects.requireNonNull(suffix, "The suffix must not be null");
129 // make defensive copies of arguments
130 this.prefix = prefix.toString();
131 this.delimiter = delimiter.toString();
132 this.suffix = suffix.toString();
133 }
134
135 /**
136 * Sets the sequence of characters to be used when determining the string
137 * representation of this {@code StringJoiner} and no elements have been
138 * added yet, that is, when it is empty. A copy of the {@code emptyValue}
139 * parameter is made for this purpose. Note that once an add method has been
140 * called, the {@code StringJoiner} is no longer considered empty, even if
141 * the element(s) added correspond to the empty {@code String}.
142 *
143 * @param emptyValue the characters to return as the value of an empty
144 * {@code StringJoiner}
145 * @return this {@code StringJoiner} itself so the calls may be chained
146 * @throws NullPointerException when the {@code emptyValue} parameter is
147 * {@code null}
148 */
149 public StringJoiner setEmptyValue(CharSequence emptyValue) {
150 this.emptyValue = Objects.requireNonNull(emptyValue,
151 "The empty value must not be null").toString();
152 return this;
153 }
154
155 private static int getChars(String s, char[] chars, int start) {
156 int len = s.length();
157 s.getChars(0, len, chars, start);
158 return len;
159 }
160
161 /**
162 * Returns the current value, consisting of the {@code prefix}, the values
163 * added so far separated by the {@code delimiter}, and the {@code suffix},
164 * unless no elements have been added in which case, the
165 * {@code prefix + suffix} or the {@code emptyValue} characters are returned.
166 *
167 * @return the string representation of this {@code StringJoiner}
168 */
169 @Override
170 public String toString() {
171 final String[] elts = this.elts;
172 if (elts == null && emptyValue != null) {
173 return emptyValue;
174 }
175 final int size = this.size;
176 final int addLen = prefix.length() + suffix.length();
177 if (addLen == 0) {
178 compactElts();
179 return size == 0 ? "" : elts[0];
180 }
181 final String delimiter = this.delimiter;
182 final char[] chars = new char[len + addLen];
183 int k = getChars(prefix, chars, 0);
184 if (size > 0) {
185 k += getChars(elts[0], chars, k);
186 for (int i = 1; i < size; i++) {
187 k += getChars(delimiter, chars, k);
188 k += getChars(elts[i], chars, k);
189 }
190 }
191 k += getChars(suffix, chars, k);
192 return jla.newStringUnsafe(chars);
193 }
194
195 /**
196 * Adds a copy of the given {@code CharSequence} value as the next
197 * element of the {@code StringJoiner} value. If {@code newElement} is
198 * {@code null}, then {@code "null"} is added.
199 *
200 * @param newElement The element to add
201 * @return a reference to this {@code StringJoiner}
202 */
203 public StringJoiner add(CharSequence newElement) {
204 final String elt = String.valueOf(newElement);
205 if (elts == null) {
206 elts = new String[8];
207 } else {
208 if (size == elts.length)
209 elts = Arrays.copyOf(elts, 2 * size);
210 len += delimiter.length();
211 }
212 len += elt.length();
213 elts[size++] = elt;
214 return this;
215 }
216
217 /**
218 * Adds the contents of the given {@code StringJoiner} without prefix and
219 * suffix as the next element if it is non-empty. If the given {@code
220 * StringJoiner} is empty, the call has no effect.
221 *
222 * <p>A {@code StringJoiner} is empty if {@link #add(CharSequence) add()}
223 * has never been called, and if {@code merge()} has never been called
224 * with a non-empty {@code StringJoiner} argument.
225 *
226 * <p>If the other {@code StringJoiner} is using a different delimiter,
227 * then elements from the other {@code StringJoiner} are concatenated with
228 * that delimiter and the result is appended to this {@code StringJoiner}
229 * as a single element.
230 *
231 * @param other The {@code StringJoiner} whose contents should be merged
232 * into this one
233 * @throws NullPointerException if the other {@code StringJoiner} is null
234 * @return This {@code StringJoiner}
235 */
236 public StringJoiner merge(StringJoiner other) {
237 Objects.requireNonNull(other);
238 if (other.elts == null) {
239 return this;
240 }
241 other.compactElts();
242 return add(other.elts[0]);
243 }
244
245 private void compactElts() {
246 if (size > 1) {
247 final char[] chars = new char[len];
248 int i = 1, k = getChars(elts[0], chars, 0);
249 do {
250 k += getChars(delimiter, chars, k);
251 k += getChars(elts[i], chars, k);
252 elts[i] = null;
253 } while (++i < size);
254 size = 1;
255 elts[0] = jla.newStringUnsafe(chars);
256 }
257 }
258
259 /**
260 * Returns the length of the {@code String} representation
261 * of this {@code StringJoiner}. Note that if
262 * no add methods have been called, then the length of the {@code String}
263 * representation (either {@code prefix + suffix} or {@code emptyValue})
264 * will be returned. The value should be equivalent to
265 * {@code toString().length()}.
266 *
267 * @return the length of the current value of {@code StringJoiner}
268 */
269 public int length() {
270 return (size == 0 && emptyValue != null) ? emptyValue.length() :
271 len + prefix.length() + suffix.length();
272 }
273 }
|