提交 a655c4a6 编写于 作者: J jgish

5015163: (str) String merge/join that is the inverse of String.split()

7172553: A utility class that forms the basis of a String.join() operation
Summary: Integrate StringJoiner changes from lambda
Reviewed-by: alanb, mduigou
上级 40aa4456
...@@ -252,6 +252,7 @@ JAVA_JAVA_java = \ ...@@ -252,6 +252,7 @@ JAVA_JAVA_java = \
java/util/Scanner.java \ java/util/Scanner.java \
java/util/InputMismatchException.java \ java/util/InputMismatchException.java \
java/util/Stack.java \ java/util/Stack.java \
java/util/StringJoiner.java \
java/util/StringTokenizer.java \ java/util/StringTokenizer.java \
java/util/TimeZone.java \ java/util/TimeZone.java \
java/util/SimpleTimeZone.java \ java/util/SimpleTimeZone.java \
......
/* /*
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,6 +34,7 @@ import java.util.Comparator; ...@@ -34,6 +34,7 @@ import java.util.Comparator;
import java.util.Formatter; import java.util.Formatter;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.StringJoiner;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
...@@ -131,7 +132,7 @@ public final class String ...@@ -131,7 +132,7 @@ public final class String
* string instance within the stream. * string instance within the stream.
*/ */
private static final ObjectStreamField[] serialPersistentFields = private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0]; new ObjectStreamField[0];
/** /**
* Initializes a newly created {@code String} object so that it represents * Initializes a newly created {@code String} object so that it represents
...@@ -970,7 +971,7 @@ public final class String ...@@ -970,7 +971,7 @@ public final class String
return true; return true;
} }
if (anObject instanceof String) { if (anObject instanceof String) {
String anotherString = (String) anObject; String anotherString = (String)anObject;
int n = value.length; int n = value.length;
if (n == anotherString.value.length) { if (n == anotherString.value.length) {
char v1[] = value; char v1[] = value;
...@@ -978,7 +979,7 @@ public final class String ...@@ -978,7 +979,7 @@ public final class String
int i = 0; int i = 0;
while (n-- != 0) { while (n-- != 0) {
if (v1[i] != v2[i]) if (v1[i] != v2[i])
return false; return false;
i++; i++;
} }
return true; return true;
...@@ -1003,7 +1004,7 @@ public final class String ...@@ -1003,7 +1004,7 @@ public final class String
* @since 1.4 * @since 1.4
*/ */
public boolean contentEquals(StringBuffer sb) { public boolean contentEquals(StringBuffer sb) {
return contentEquals((CharSequence) sb); return contentEquals((CharSequence)sb);
} }
private boolean nonSyncContentEquals(AbstractStringBuilder sb) { private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
...@@ -1248,7 +1249,8 @@ public final class String ...@@ -1248,7 +1249,8 @@ public final class String
* argument. * argument.
* <li>There is some nonnegative integer <i>k</i> less than {@code len} * <li>There is some nonnegative integer <i>k</i> less than {@code len}
* such that: * such that:
* <code>this.charAt(toffset+<i>k</i>)&nbsp;!=&nbsp;other.charAt(ooffset+<i>k</i>)</code> * {@code this.charAt(toffset + }<i>k</i>{@code ) != other.charAt(ooffset + }
* <i>k</i>{@code )}
* </ul> * </ul>
* *
* @param toffset the starting offset of the subregion in this string. * @param toffset the starting offset of the subregion in this string.
...@@ -1872,7 +1874,7 @@ public final class String ...@@ -1872,7 +1874,7 @@ public final class String
int min = sourceOffset + targetCount - 1; int min = sourceOffset + targetCount - 1;
int i = min + fromIndex; int i = min + fromIndex;
startSearchForLastChar: startSearchForLastChar:
while (true) { while (true) {
while (i >= min && source[i] != strLastChar) { while (i >= min && source[i] != strLastChar) {
i--; i--;
...@@ -1973,7 +1975,7 @@ public final class String ...@@ -1973,7 +1975,7 @@ public final class String
* str.substring(begin,&nbsp;end)</pre></blockquote> * str.substring(begin,&nbsp;end)</pre></blockquote>
* *
* This method is defined so that the {@code String} class can implement * This method is defined so that the {@code String} class can implement
* the {@link CharSequence} interface. </p> * the {@link CharSequence} interface.
* *
* @param beginIndex the begin index, inclusive. * @param beginIndex the begin index, inclusive.
* @param endIndex the end index, exclusive. * @param endIndex the end index, exclusive.
...@@ -2352,9 +2354,11 @@ public final class String ...@@ -2352,9 +2354,11 @@ public final class String
// Construct result // Construct result
int resultSize = list.size(); int resultSize = list.size();
if (limit == 0) if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--; resultSize--;
}
}
String[] result = new String[resultSize]; String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result); return list.subList(0, resultSize).toArray(result);
} }
...@@ -2403,6 +2407,90 @@ public final class String ...@@ -2403,6 +2407,90 @@ public final class String
return split(regex, 0); return split(regex, 0);
} }
/**
* Returns a new String composed of copies of the
* {@code CharSequence elements} joined together with a copy of
* the specified {@code delimiter}.
*
* <blockquote>For example,
* <pre>{@code
* String message = String.join("-", "Java", "is", "cool");
* // message returned is: "Java-is-cool"
* }</pre></blockquote>
*
* Note that if an element is null, then {@code "null"} is added.
*
* @param delimiter the delimiter that separates each element
* @param elements the elements to join together.
*
* @return a new {@code String} that is composed of the {@code elements}
* separated by the {@code delimiter}
*
* @throws NullPointerException If {@code delimiter} or {@code elements}
* is {@code null}
*
* @see java.util.StringJoiner
* @since 1.8
*/
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// Number of elements not likely worth Arrays.stream overhead.
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
/**
* Returns a new {@code String} composed of copies of the
* {@code CharSequence elements} joined together with a copy of the
* specified {@code delimiter}.
*
* <blockquote>For example,
* <pre>{@code
* List<String> strings = new LinkedList<>();
* strings.add("Java");strings.add("is");
* strings.add("cool");
* String message = String.join(" ", strings);
* //message returned is: "Java is cool"
*
* Set<String> strings = new HashSet<>();
* Strings.add("Java"); strings.add("is");
* strings.add("very"); strings.add("cool");
* String message = String.join("-", strings);
* //message returned is: "Java-is-very-cool"
* }</pre></blockquote>
*
* Note that if an individual element is {@code null}, then {@code "null"} is added.
*
* @param delimiter a sequence of characters that is used to separate each
* of the {@code elements} in the resulting {@code String}
* @param elements an {@code Iterable} that will have its {@code elements}
* joined together.
*
* @return a new {@code String} that is composed from the {@code elements}
* argument
*
* @throws NullPointerException If {@code delimiter} or {@code elements}
* is {@code null}
*
* @see #join(CharSequence,CharSequence...)
* @see java.util.StringJoiner
* @since 1.8
*/
public static String join(CharSequence delimiter,
Iterable<? extends CharSequence> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
/** /**
* Converts all of the characters in this {@code String} to lower * Converts all of the characters in this {@code String} to lower
* case using the rules of the given {@code Locale}. Case mapping is based * case using the rules of the given {@code Locale}. Case mapping is based
...@@ -2650,9 +2738,9 @@ public final class String ...@@ -2650,9 +2738,9 @@ public final class String
return this; return this;
} }
/* result may grow, so i+resultOffset is the write location in result */
int resultOffset = 0;
char[] result = new char[len]; /* may grow */ char[] result = new char[len]; /* may grow */
int resultOffset = 0; /* result may grow, so i+resultOffset
* is the write location in result */
/* Just copy the first few upperCase characters. */ /* Just copy the first few upperCase characters. */
System.arraycopy(value, 0, result, 0, firstLower); System.arraycopy(value, 0, result, 0, firstLower);
...@@ -2757,7 +2845,7 @@ public final class String ...@@ -2757,7 +2845,7 @@ public final class String
* object is created, representing the substring of this string that * object is created, representing the substring of this string that
* begins with the character at index <i>k</i> and ends with the * begins with the character at index <i>k</i> and ends with the
* character at index <i>m</i>-that is, the result of * character at index <i>m</i>-that is, the result of
* <code>this.substring(<i>k</i>,&nbsp;<i>m</i>+1)</code>. * {@code this.substring(k, m + 1)}.
* <p> * <p>
* This method may be used to trim whitespace (as defined above) from * This method may be used to trim whitespace (as defined above) from
* the beginning and end of a string. * the beginning and end of a string.
...@@ -3143,8 +3231,8 @@ public final class String ...@@ -3143,8 +3231,8 @@ public final class String
* programmer should be aware that producing distinct integer results * programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables. * for unequal objects may improve the performance of hash tables.
* </ul> * </ul>
* </p> *
* The hash value will never be zero. * The hash value will never be zero.
* *
* @return a hash code value for this object. * @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object) * @see java.lang.Object#equals(java.lang.Object)
......
/*
* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.util;
/**
* {@code StringJoiner} is used to construct a sequence of characters separated
* by a delimiter and optionally starting with a supplied prefix
* and ending with a supplied suffix.
* <p>
* For example, the String {@code "[George:Sally:Fred]"} may
* be constructed as follows:
* <pre> {@code
* StringJoiner sj = new StringJoiner(":", "[", "]");
* sj.add("George").add("Sally").add("Fred");
* String desiredString = sj.toString();
* }</pre>
* <p>
* Prior to adding something to the {@code StringJoiner}, its
* {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
* However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
* supplied will be returned instead. This can be used, for example, when
* creating a string using set notation to indicate an empty set, i.e.
* <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
* {@code suffix} is <code>"}"</code> and nothing has been added to the
* {@code StringJoiner}.
* <p>
* A {@code StringJoiner} may be employed to create formatted output from a
* collection using lambda expressions as shown in the following example.
*
* <pre> {@code
* List<Person> people = ...
* String commaSeparatedNames =
* people.map(p -> p.getName()).into(new StringJoiner(", ")).toString();
* }</pre>
*
* @author Jim Gish
* @since 1.8
*/
public final class StringJoiner {
private final String prefix;
private final String delimiter;
private final String suffix;
/*
* StringBuilder value -- at any time, the characters constructed from the
* prefix, the added element separated by the delimiter, but without the
* suffix, so that we can more easily add elements without having to jigger
* the suffix each time.
*/
private StringBuilder value;
/*
* By default, the string consisting of prefix+suffix, returned by
* toString(), or properties of value, when no elements have yet been added,
* i.e. when it is empty. This may be overridden by the user to be some
* other value including the empty String.
*/
private String emptyValue;
/**
* Constructs a {@code StringJoiner} with no characters in it, with no
* {@code prefix} or {@code suffix}, and a copy of the supplied
* {@code delimiter}.
* If no characters are added to the {@code StringJoiner} and methods
* accessing the value of it are invoked, it will not return a
* {@code prefix} or {@code suffix} (or properties thereof) in the result,
* unless {@code setEmptyValue} has first been called.
*
* @param delimiter the sequence of characters to be used between each
* element added to the {@code StringJoiner} value
* @throws NullPointerException if {@code delimiter} is {@code null}
*/
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");
}
/**
* Constructs a {@code StringJoiner} with no characters in it using copies
* of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
* If no characters are added to the {@code StringJoiner} and methods
* accessing the string value of it are invoked, it will return the
* {@code prefix + suffix} (or properties thereof) in the result, unless
* {@code setEmptyValue} has first been called.
*
* @param delimiter the sequence of characters to be used between each
* element added to the {@code StringJoiner}
* @param prefix the sequence of characters to be used at the beginning
* @param suffix the sequence of characters to be used at the end
* @throws NullPointerException if {@code prefix}, {@code delimiter}, or
* {@code suffix} is {@code null}
*/
public StringJoiner(CharSequence delimiter, CharSequence prefix,
CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
// make defensive copies of arguments
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
this.emptyValue = this.prefix + this.suffix;
}
/**
* Sets the sequence of characters to be used when determining the string
* representation of this {@code StringJoiner} and no elements have been
* added yet, i.e. when it is empty. A copy of the {@code emptyValue}
* parameter is made for this purpose. Note that once an add method has been
* called, the {@code StringJoiner} is no longer considered empty, even if
* the element(s) added correspond to the empty {@code String}.
*
* @param emptyValue the characters to return as the value of an empty
* {@code StringJoiner}
* @return this {@code StringJoiner} itself so the calls may be chained
* @throws NullPointerException when the {@code emptyValue} parameter is
* {@code null}
*/
public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
/**
* Returns the current value, consisting of the {@code prefix}, the values
* added so far separated by the {@code delimiter}, and the {@code suffix},
* unless no elements have been added in which case, the
* {@code prefix + suffix} or the {@code emptyValue} characters are returned
*
* @return the string representation of this {@code StringJoiner}
*/
@Override
public String toString() {
if (value == null) {
return emptyValue;
} else {
if (suffix.equals("")) {
return value.toString();
} else {
int initialLength = value.length();
String result = value.append(suffix).toString();
// reset value to pre-append initialLength
value.setLength(initialLength);
return result;
}
}
}
/**
* Add the a copy of the supplied {@code CharSequence} value as the next
* element of the {@code StringJoiner} value. If {@code newElement} is
* {@code null}, then {@code "null"} is added.
*
* @param newElement The element to add
* @return a reference to this {@code StringJoiner}
*/
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
/**
* The length of the {@code StringJoiner} value, i.e. the length of
* {@code String} representation of the {@code StringJoiner}. Note that if
* no add methods have been called, then the length of the {@code String}
* representation (either {@code prefix + suffix} or {@code emptyValue})
* will be returned. The value should be equivalent to
* {@code toString().length()}.
*
* @return the length of the current value of {@code StringJoiner}
*/
public int length() {
// Remember that we never actually append the suffix unless we return
// the full (present) value or some sub-string or length of it, so that
// we can add on more if we need to.
return (value != null ? value.length() + suffix.length() :
emptyValue.length());
}
}
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test @bug 5015163
* @summary test String merge/join that is the inverse of String.split()
* @run testng StringJoinTest
* @author Jim Gish
*/
import java.util.ArrayList;
import java.util.List;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test(groups = {"unit","string","lang","libs"})
public class StringJoinTest {
private final static String DASH = "-";
private final static String BEGIN = "Hi there";
private final static String JIM = "Jim";
private final static String JOHN = "John";
private final static String AND_JOE = "and Joe";
private final static String BILL = "Bill";
private final static String BOB = "Bob";
private final static String AND_BO = "and Bo";
private final static String ZEKE = "Zeke";
private final static String ZACK = "Zack";
private final static String AND_ZOE = "and Zoe";
/**
* Tests the join() methods on String
*/
public void testJoinStringVarargs() {
// check a non-null join of String array (var-args) elements
String expectedResult = BEGIN + DASH + JIM + DASH + JOHN + DASH + AND_JOE;
String result = String.join(DASH, BEGIN, JIM, JOHN, AND_JOE);
assertEquals(result, expectedResult, "BEGIN.join(DASH, JIM, JOHN, AND_JOE)");
// test with just one element
assertEquals(String.join(DASH, BEGIN), BEGIN);
}
public void testJoinStringArray() {
// check a non-null join of Object[] with String elements
String[] theBs = {BILL, BOB, AND_BO};
String result = String.join(DASH, theBs);
String expectedResult = BILL + DASH + BOB + DASH + AND_BO;
assertEquals(result, expectedResult, "String.join(DASH, theBs)");
}
public void testJoinEmptyStringArray() {
// check a non-null join of Object[] with String elements
String[] empties = {};
String result = String.join(DASH, empties);
assertEquals(result, "", "String.join(DASH, empties)");
}
@Test(expectedExceptions = {NullPointerException.class})
public void testJoinNullStringArray() {
// check a non-null join of Object[] with String elements
String[] empties = null;
String result = String.join(DASH, empties);
}
@Test(expectedExceptions = {NullPointerException.class})
public void testJoinNullIterableStringList() {
// check join of an Iterables
List<CharSequence> theZsList = null;
String.join(DASH, theZsList);
}
public void testJoinIterableStringList() {
// check join of an Iterables
List<CharSequence> theZsList = new ArrayList<>();
theZsList.add(ZEKE);
theZsList.add(ZACK);
theZsList.add(AND_ZOE);
assertEquals(String.join(DASH, theZsList), ZEKE + DASH + ZACK + DASH
+ AND_ZOE, "String.join(DASH, theZsList))");
}
public void testJoinNullStringList() {
List<CharSequence> nullList = null;
try {
assertEquals( String.join( DASH, nullList ), "null" );
fail("Null container should cause NPE");
} catch (NullPointerException npe) {}
assertEquals(String.join(DASH, null, null), "null" + DASH + "null");
}
@Test(expectedExceptions = {NullPointerException.class})
public void testJoinNullDelimiter() {
String.join(null, JIM, JOHN);
}
}
/*
* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 5015163 7172553
* @summary tests StringJoinerTest
* @run testng StringJoinerTest
* @author Jim Gish
*/
import java.util.StringJoiner;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
@Test(groups = {"unit","string","util","libs"})
public class StringJoinerTest {
private static final String EMPTY = "EMPTY";
private static final String ONE = "One";
private static final int ONE_LEN = ONE.length();
private static final String TWO = "Two";
private static final int TWO_LEN = TWO.length();
private static final String THREE = "Three";
private static final String FOUR = "Four";
private static final String FIVE = "Five";
private static final String DASH = "-";
/* Uncomment when we have streams
public void addAddAll() {
StringJoiner sj = new StringJoiner(DASH, "{", "}");
sj.add(ONE);
ArrayList<String> nextOne = new ArrayList<>();
nextOne.add(TWO);
nextOne.add(THREE);
nextOne.stream().forEach(sj::add);
String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}";
assertEquals(sj.toString(), expected);
}
void addAlladd() {
StringJoiner sj = new StringJoiner(DASH, "{", "}");
ArrayList<String> firstOne = new ArrayList<>();
firstOne.add(ONE);
firstOne.add(TWO);
firstOne.stream().forEach(sj::add);
sj.add(THREE);
String expected = "{"+ONE+DASH+TWO+DASH+THREE+"}";
assertEquals(sj.toString(), expected);
}
// The following tests do two successive adds of different types
public void addAlladdAll() {
StringJoiner sj = new StringJoiner(DASH, "{", "}");
ArrayList<String> firstOne = new ArrayList<>();
firstOne.add(ONE);
firstOne.add(TWO);
firstOne.add(THREE);
firstOne.stream().forEach(sj::add);
ArrayList<String> nextOne = new ArrayList<>();
nextOne.add(FOUR);
nextOne.add(FIVE);
nextOne.stream().forEach(sj::add);
String expected = "{"+ONE+DASH+TWO+DASH+THREE+DASH+FOUR+DASH+FIVE+"}";
assertEquals(sj.toString(), expected);
}
public void testInto() {
ArrayList<String> list = new ArrayList<>();
list.add(ONE);
list.add(TWO);
list.add(THREE);
StringJoiner target = new StringJoiner(",", "{", "}");
assertEquals(target.toString(), "{" + ONE + "," + TWO + "," + THREE +
"}");
}
*/
public void addCharSequence() {
StringJoiner sj = new StringJoiner(",");
CharSequence cs_one = ONE;
CharSequence cs_two = TWO;
sj.add(cs_one);
sj.add(cs_two);
assertEquals(sj.toString(), ONE + "," + TWO);
sj = new StringJoiner(DASH, "{", "}");
sj.add(cs_one);
sj.add(cs_two);
assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}");
StringBuilder builder = new StringBuilder(ONE);
StringBuffer buffer = new StringBuffer(THREE);
sj = new StringJoiner(", ", "{ ", " }");
sj.add(builder).add(buffer);
builder.append(TWO);
buffer.append(FOUR);
assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + " }",
"CharSequence is copied when add");
sj.add(builder);
assertEquals(sj.toString(), "{ " + ONE + ", " + THREE + ", " + ONE +
TWO + " }");
}
public void addCharSequenceWithEmptyValue() {
StringJoiner sj = new StringJoiner(",").setEmptyValue(EMPTY);
CharSequence cs_one = ONE;
CharSequence cs_two = TWO;
sj.add(cs_one);
sj.add(cs_two);
assertEquals(sj.toString(), ONE + "," + TWO);
sj = new StringJoiner(DASH, "{", "}");
sj.add(cs_one);
sj.add(cs_two);
assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}");
sj = new StringJoiner(DASH, "{", "}");
assertEquals(sj.toString(), "{}");
sj = new StringJoiner("=", "{", "}").setEmptyValue("");
assertEquals(sj.toString(), "");
sj = new StringJoiner(DASH, "{", "}").setEmptyValue(EMPTY);
assertEquals(sj.toString(), EMPTY);
sj.add(cs_one);
sj.add(cs_two);
assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}");
}
public void addString() {
StringJoiner sj = new StringJoiner(DASH);
sj.add(ONE);
assertEquals(sj.toString(), ONE);
sj = new StringJoiner(DASH, "{", "}");
sj.add(ONE);
assertEquals(sj.toString(), "{" + ONE + "}");
sj.add(TWO);
assertEquals(sj.toString(), "{" + ONE + DASH + TWO + "}");
}
public void lengthWithCustomEmptyValue() {
StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY);
assertEquals(sj.length(), EMPTY.length());
sj.add("");
assertEquals(sj.length(), "<>".length());
sj.add("");
assertEquals(sj.length(), "<->".length());
sj.add(ONE);
assertEquals(sj.length(), 4 + ONE_LEN);
assertEquals(sj.toString().length(), sj.length());
sj.add(TWO);
assertEquals(sj.length(), 5 + ONE_LEN + TWO_LEN);
assertEquals(sj.toString().length(), sj.length());
sj = new StringJoiner("||", "<", "-->");
assertEquals(sj.length(), 4);
assertEquals(sj.toString().length(), sj.length());
sj.add("abcdef");
assertEquals(sj.length(), 10);
assertEquals(sj.toString().length(), sj.length());
sj.add("xyz");
assertEquals(sj.length(), 15);
assertEquals(sj.toString().length(), sj.length());
}
public void noAddAndEmptyValue() {
StringJoiner sj = new StringJoiner(DASH, "", "").setEmptyValue(EMPTY);
assertEquals(sj.toString(), EMPTY);
sj = new StringJoiner(DASH, "<..", "");
assertEquals(sj.toString(), "<..");
sj = new StringJoiner(DASH, "<..", "");
assertEquals(sj.toString(), "<..");
sj = new StringJoiner(DASH, "", "==>");
assertEquals(sj.toString(), "==>");
sj = new StringJoiner(DASH, "{", "}");
assertEquals(sj.toString(), "{}");
}
@Test(expectedExceptions = {NullPointerException.class})
public void setEmptyValueNull() {
new StringJoiner(DASH, "{", "}").setEmptyValue(null);
}
@Test(expectedExceptions = {NullPointerException.class})
public void setDelimiterNull() {
new StringJoiner(null);
}
@Test(expectedExceptions = {NullPointerException.class})
public void setPrefixNull() {
new StringJoiner(DASH, null, "}");
}
@Test(expectedExceptions = {NullPointerException.class})
public void setSuffixNull() {
new StringJoiner(DASH, "{", null);
}
public void stringFromtoString() {
StringJoiner sj = new StringJoiner(", ");
assertEquals(sj.toString(), "");
sj = new StringJoiner(",", "{", "}");
assertEquals(sj.toString(), "{}");
sj = new StringJoiner(",");
sj.add(ONE);
assertEquals(sj.toString(), ONE);
sj.add(TWO);
assertEquals(sj.toString(), ONE + "," + TWO);
sj = new StringJoiner(",", "{--", "--}");
sj.add(ONE);
sj.add(TWO);
assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}");
}
public void stringFromtoStringWithEmptyValue() {
StringJoiner sj = new StringJoiner(" ", "", "");
assertEquals(sj.toString(), "");
sj = new StringJoiner(", ");
assertEquals(sj.toString(), "");
sj = new StringJoiner(",", "{", "}");
assertEquals(sj.toString(), "{}");
sj = new StringJoiner(",", "{", "}").setEmptyValue("");
assertEquals(sj.toString(), "");
sj = new StringJoiner(",");
sj.add(ONE);
assertEquals(sj.toString(), ONE);
sj.add(TWO);
assertEquals(sj.toString(), ONE + "," + TWO);
sj = new StringJoiner(",", "{--", "--}");
sj.add(ONE);
assertEquals(sj.toString(), "{--" + ONE + "--}" );
sj.add(TWO);
assertEquals(sj.toString(), "{--" + ONE + "," + TWO + "--}");
}
public void toStringWithCustomEmptyValue() {
StringJoiner sj = new StringJoiner(DASH, "<", ">").setEmptyValue(EMPTY);
assertEquals(sj.toString(), EMPTY);
sj.add("");
assertEquals(sj.toString(), "<>");
sj.add("");
assertEquals(sj.toString(), "<->");
}
private void testCombos(String infix, String prefix, String suffix) {
StringJoiner sj = new StringJoiner(infix, prefix, suffix);
assertEquals(sj.toString(), prefix + suffix);
assertEquals(sj.toString().length(), sj.length());
// EmptyValue
sj = new StringJoiner(infix, prefix, suffix).setEmptyValue("<NONE>");
assertEquals(sj.toString(), "<NONE>");
assertEquals(sj.toString().length(), sj.length());
// empty in front
sj.add("");
assertEquals(sj.toString(), prefix + suffix);
// empty in middle
sj.add("");
assertEquals(sj.toString(), prefix + infix + suffix);
sj.add("1");
assertEquals(sj.toString(), prefix + infix + infix + "1" + suffix);
// empty at end
sj.add("");
assertEquals(sj.toString(), prefix + infix + infix + "1" + infix + suffix);
sj = new StringJoiner(infix, prefix, suffix).setEmptyValue("<NONE>");
sj.add("1");
assertEquals(sj.toString(), prefix + "1" + suffix);
sj.add("2");
assertEquals(sj.toString(), prefix + "1" + infix + "2" + suffix);
sj.add("");
assertEquals(sj.toString(), prefix + "1" + infix + "2" +infix + suffix);
sj.add("3");
assertEquals(sj.toString(), prefix + "1" + infix + "2" +infix + infix + "3" + suffix);
}
public void testDelimiterCombinations() {
testCombos("", "", "");
testCombos("", "<", "");
testCombos("", "", ">");
testCombos("", "<", ">");
testCombos(",", "", "");
testCombos(",", "<", "");
testCombos(",", "", ">");
testCombos(",", "<", ">");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册