8137326: Methods for comparing CharSequence, StringBuilder, and StringBuffer
Reviewed-by: rriggs, smarks, sherman, tvaleev
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -89,6 +89,29 @@
}
/**
+ * Compares the objects of two AbstractStringBuilder implementations lexicographically.
+ *
+ * @since 11
+ */
+ int compareTo(AbstractStringBuilder another) {
+ if (this == another) {
+ return 0;
+ }
+
+ byte val1[] = value;
+ byte val2[] = another.value;
+ int count1 = this.count;
+ int count2 = another.count;
+
+ if (coder == another.coder) {
+ return isLatin1() ? StringLatin1.compareTo(val1, val2, count1, count2)
+ : StringUTF16.compareTo(val1, val2, count1, count2);
+ }
+ return isLatin1() ? StringLatin1.compareToUTF16(val1, val2, count1, count2)
+ : StringUTF16.compareToLatin1(val1, val2, count1, count2);
+ }
+
+ /**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
--- a/src/java.base/share/classes/java/lang/CharSequence.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/CharSequence.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -26,6 +26,7 @@
package java.lang;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -43,9 +44,9 @@
*
* <p> This interface does not refine the general contracts of the {@link
* java.lang.Object#equals(java.lang.Object) equals} and {@link
- * java.lang.Object#hashCode() hashCode} methods. The result of comparing two
- * objects that implement {@code CharSequence} is therefore, in general,
- * undefined. Each object may be implemented by a different class, and there
+ * java.lang.Object#hashCode() hashCode} methods. The result of testing two objects
+ * that implement {@code CharSequence} for equality is therefore, in general, undefined.
+ * Each object may be implemented by a different class, and there
* is no guarantee that each class will be capable of testing its instances
* for equality with those of the other. It is therefore inappropriate to use
* arbitrary {@code CharSequence} instances as elements in a set or as keys in
@@ -237,4 +238,54 @@
Spliterator.ORDERED,
false);
}
+
+ /**
+ * Compares two {@code CharSequence} instances lexicographically. Returns a
+ * negative value, zero, or a positive value if the first sequence is lexicographically
+ * less than, equal to, or greater than the second, respectively.
+ *
+ * <p>
+ * The lexicographical ordering of {@code CharSequence} is defined as follows.
+ * Consider a {@code CharSequence} <i>cs</i> of length <i>len</i> to be a
+ * sequence of char values, <i>cs[0]</i> to <i>cs[len-1]</i>. Suppose <i>k</i>
+ * is the lowest index at which the corresponding char values from each sequence
+ * differ. The lexicographic ordering of the sequences is determined by a numeric
+ * comparison of the char values <i>cs1[k]</i> with <i>cs2[k]</i>. If there is
+ * no such index <i>k</i>, the shorter sequence is considered lexicographically
+ * less than the other. If the sequences have the same length, the sequences are
+ * considered lexicographically equal.
+ *
+ *
+ * @param cs1 the first {@code CharSequence}
+ * @param cs2 the second {@code CharSequence}
+ *
+ * @return the value {@code 0} if the two {@code CharSequence} are equal;
+ * a negative integer if the first {@code CharSequence}
+ * is lexicographically less than the second; or a
+ * positive integer if the first {@code CharSequence} is
+ * lexicographically greater than the second.
+ *
+ * @since 11
+ */
+ @SuppressWarnings("unchecked")
+ public static int compare(CharSequence cs1, CharSequence cs2) {
+ if (Objects.requireNonNull(cs1) == Objects.requireNonNull(cs2)) {
+ return 0;
+ }
+
+ if (cs1.getClass() == cs2.getClass() && cs1 instanceof Comparable) {
+ return ((Comparable<Object>) cs1).compareTo(cs2);
+ }
+
+ for (int i = 0, len = Math.min(cs1.length(), cs2.length()); i < len; i++) {
+ char a = cs1.charAt(i);
+ char b = cs2.charAt(i);
+ if (a != b) {
+ return a - b;
+ }
+ }
+
+ return cs1.length() - cs2.length();
+ }
+
}
--- a/src/java.base/share/classes/java/lang/StringBuffer.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/StringBuffer.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, 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
@@ -90,6 +90,14 @@
* this one, as it supports all of the same operations but it is faster, as
* it performs no synchronization.
*
+ * @apiNote
+ * {@code StringBuffer} implements {@code Comparable} but does not override
+ * {@link Object#equals equals}. Thus, the natural ordering of {@code StringBuffer}
+ * is inconsistent with equals. Care should be exercised if {@code StringBuffer}
+ * objects are used as keys in a {@code SortedMap} or elements in a {@code SortedSet}.
+ * See {@link Comparable}, {@link java.util.SortedMap SortedMap}, or
+ * {@link java.util.SortedSet SortedSet} for more information.
+ *
* @author Arthur van Hoff
* @see java.lang.StringBuilder
* @see java.lang.String
@@ -97,7 +105,7 @@
*/
public final class StringBuffer
extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
+ implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
/**
@@ -162,6 +170,35 @@
append(seq);
}
+ /**
+ * Compares two {@code StringBuffer} instances lexicographically. This method
+ * follows the same rules for lexicographical comparison as defined in the
+ * {@linkplain java.lang.CharSequence#compare(java.lang.CharSequence,
+ * java.lang.CharSequence) CharSequence.compare(this, another)} method.
+ *
+ * <p>
+ * For finer-grained, locale-sensitive String comparison, refer to
+ * {@link java.text.Collator}.
+ *
+ * @implNote
+ * This method synchronizes on {@code this}, the current object, but not
+ * {@code StringBuffer another} with which {@code this StringBuffer} is compared.
+ *
+ * @param another the {@code StringBuffer} to be compared with
+ *
+ * @return the value {@code 0} if this {@code StringBuffer} contains the same
+ * character sequence as that of the argument {@code StringBuffer}; a negative integer
+ * if this {@code StringBuffer} is lexicographically less than the
+ * {@code StringBuffer} argument; or a positive integer if this {@code StringBuffer}
+ * is lexicographically greater than the {@code StringBuffer} argument.
+ *
+ * @since 11
+ */
+ @Override
+ public synchronized int compareTo(StringBuffer another) {
+ return super.compareTo(another);
+ }
+
@Override
public synchronized int length() {
return count;
--- a/src/java.base/share/classes/java/lang/StringBuilder.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/StringBuilder.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -69,6 +69,14 @@
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
+ * @apiNote
+ * {@code StringBuilder} implements {@code Comparable} but does not override
+ * {@link Object#equals equals}. Thus, the natural ordering of {@code StringBuilder}
+ * is inconsistent with equals. Care should be exercised if {@code StringBuilder}
+ * objects are used as keys in a {@code SortedMap} or elements in a {@code SortedSet}.
+ * See {@link Comparable}, {@link java.util.SortedMap SortedMap}, or
+ * {@link java.util.SortedSet SortedSet} for more information.
+ *
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
@@ -76,7 +84,7 @@
*/
public final class StringBuilder
extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
+ implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
/** use serialVersionUID for interoperability */
@@ -130,6 +138,31 @@
append(seq);
}
+ /**
+ * Compares two {@code StringBuilder} instances lexicographically. This method
+ * follows the same rules for lexicographical comparison as defined in the
+ * {@linkplain java.lang.CharSequence#compare(java.lang.CharSequence,
+ * java.lang.CharSequence) CharSequence.compare(this, another)} method.
+ *
+ * <p>
+ * For finer-grained, locale-sensitive String comparison, refer to
+ * {@link java.text.Collator}.
+ *
+ * @param another the {@code StringBuilder} to be compared with
+ *
+ * @return the value {@code 0} if this {@code StringBuilder} contains the same
+ * character sequence as that of the argument {@code StringBuilder}; a negative integer
+ * if this {@code StringBuilder} is lexicographically less than the
+ * {@code StringBuilder} argument; or a positive integer if this {@code StringBuilder}
+ * is lexicographically greater than the {@code StringBuilder} argument.
+ *
+ * @since 11
+ */
+ @Override
+ public int compareTo(StringBuilder another) {
+ return super.compareTo(another);
+ }
+
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
--- a/src/java.base/share/classes/java/lang/StringLatin1.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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
@@ -103,6 +103,10 @@
public static int compareTo(byte[] value, byte[] other) {
int len1 = value.length;
int len2 = other.length;
+ return compareTo(value, other, len1, len2);
+ }
+
+ public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
if (value[k] != other[k]) {
@@ -116,6 +120,20 @@
public static int compareToUTF16(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = StringUTF16.length(other);
+ return compareToUTF16Values(value, other, len1, len2);
+ }
+
+ /*
+ * Checks the boundary and then compares the byte arrays.
+ */
+ public static int compareToUTF16(byte[] value, byte[] other, int len1, int len2) {
+ checkOffset(len1, length(value));
+ checkOffset(len2, StringUTF16.length(other));
+
+ return compareToUTF16Values(value, other, len1, len2);
+ }
+
+ private static int compareToUTF16Values(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
--- a/src/java.base/share/classes/java/lang/StringUTF16.java Thu Mar 01 21:09:54 2018 +0000
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java Thu Mar 01 15:31:04 2018 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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
@@ -273,6 +273,20 @@
public static int compareTo(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = length(other);
+ return compareValues(value, other, len1, len2);
+ }
+
+ /*
+ * Checks the boundary and then compares the byte arrays.
+ */
+ public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
+ checkOffset(len1, value);
+ checkOffset(len2, other);
+
+ return compareValues(value, other, len1, len2);
+ }
+
+ private static int compareValues(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
char c1 = getChar(value, k);
@@ -289,6 +303,10 @@
return -StringLatin1.compareToUTF16(other, value);
}
+ public static int compareToLatin1(byte[] value, byte[] other, int len1, int len2) {
+ return -StringLatin1.compareToUTF16(other, value, len2, len1);
+ }
+
public static int compareToCI(byte[] value, byte[] other) {
int len1 = length(value);
int len2 = length(other);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/CharSequence/Comparison.java Thu Mar 01 15:31:04 2018 -0800
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+import java.nio.CharBuffer;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8137326
+ * @summary Test to verify the compare method for the CharSequence class.
+ * @run testng Comparison
+ */
+public class Comparison {
+ static char SEP = ':';
+
+ static String[][] books = {
+ {"Biography", "Steve Jobs"},
+ {"Biography", "Elon Musk: Tesla, SpaceX, and the Quest for a Fantastic Future"},
+ {"Law", "Law 101: Everything You Need to Know About American Law, Fourth Edition"},
+ {"Law", "The Tools of Argument: How the Best Lawyers Think, Argue, and Win"},
+ {"History", "The History Book (Big Ideas Simply Explained)"},
+ {"History", "A People's History of the United States"},
+ };
+
+ /**
+ * Verifies the compare method by comparing StringBuilder objects with String
+ * objects.
+ */
+ @Test
+ public void compareWithString() {
+ Set<StringBuilder> sbSet = constructSBSet();
+ Set<String> sSet = constructStringSet();
+ Iterator<StringBuilder> iSB = sbSet.iterator();
+ Iterator<String> iS = sSet.iterator();
+ while (iSB.hasNext()) {
+ int result = CharSequence.compare(iSB.next(), iS.next());
+
+ Assert.assertTrue(result == 0, "Comparing item by item");
+ }
+ }
+
+ /**
+ * Verify comparison between two CharSequence implementations, including String,
+ * StringBuffer and StringBuilder.
+ *
+ * Note: CharBuffer states that "A char buffer is not comparable to any other type of object."
+ */
+ @Test
+ public void testCompare() {
+ StringBuilder sb1 = generateTestBuilder(65, 70, 97, 102);
+ StringBuilder sb2 = generateTestBuilder(65, 70, 97, 102);
+ StringBuilder sb3 = generateTestBuilder(65, 71, 97, 103);
+
+ Assert.assertTrue(CharSequence.compare(sb1, sb2) == 0, "Compare between StringBuilders");
+ Assert.assertFalse(CharSequence.compare(sb1, sb3) == 0, "Compare between StringBuilders");
+
+ Assert.assertTrue(CharSequence.compare(sb1, sb2.toString()) == 0, "Compare between a StringBuilder and String");
+ Assert.assertFalse(CharSequence.compare(sb1, sb3.toString()) == 0, "Compare between a StringBuilder and String");
+
+ StringBuffer buf1 = generateTestBuffer(65, 70, 97, 102);
+ StringBuffer buf2 = generateTestBuffer(65, 70, 97, 102);
+ StringBuffer buf3 = generateTestBuffer(65, 71, 97, 103);
+
+ Assert.assertTrue(CharSequence.compare(buf1, buf2) == 0, "Compare between StringBuffers");
+ Assert.assertFalse(CharSequence.compare(buf1, buf3) == 0, "Compare between StringBuffers");
+
+ Assert.assertTrue(CharSequence.compare(sb1, buf2) == 0, "Compare between a StringBuilder and StringBuffer");
+ Assert.assertFalse(CharSequence.compare(sb1, buf3) == 0, "Compare between a StringBuilder and StringBuffer");
+
+ CharSequence cs1 = (CharSequence)buf1;
+ CharSequence cs2 = (CharSequence)sb1;
+ @SuppressWarnings("unchecked")
+ int result = ((Comparable<Object>)cs1).compareTo(buf2);
+ Assert.assertTrue(result == 0, "Compare between a StringBuilder and StringBuffer");
+ }
+
+
+ private Set<String> constructStringSet() {
+ Set<String> sSet = new TreeSet<>();
+ for (String[] book : books) {
+ sSet.add(book[0] + SEP + book[1]);
+ }
+ return sSet;
+ }
+
+ private Set<StringBuilder> constructSBSet() {
+ Set<StringBuilder> sbSet = new TreeSet<>();
+ for (String[] book : books) {
+ sbSet.add(new StringBuilder(book[0]).append(SEP).append(book[1]));
+ }
+ return sbSet;
+ }
+
+ private static StringBuilder generateTestBuilder(int from1, int to1,
+ int from2, int to2) {
+ StringBuilder aBuffer = new StringBuilder(50);
+
+ for (int i = from1; i < to1; i++) {
+ aBuffer.append((char)i);
+ }
+ for (int i = from2; i < to2; i++) {
+ aBuffer.append((char)i);
+ }
+ return aBuffer;
+ }
+
+ private static StringBuffer generateTestBuffer(int from1, int to1,
+ int from2, int to2) {
+ StringBuffer aBuffer = new StringBuffer(50);
+
+ for (int i = from1; i < to1; i++) {
+ aBuffer.append((char)i);
+ }
+ for (int i = from2; i < to2; i++) {
+ aBuffer.append((char)i);
+ }
+ return aBuffer;
+ }
+}
--- a/test/jdk/java/lang/String/CompactString/CompareTo.java Thu Mar 01 21:09:54 2018 +0000
+++ b/test/jdk/java/lang/String/CompactString/CompareTo.java Thu Mar 01 15:31:04 2018 -0800
@@ -28,8 +28,9 @@
/*
* @test
- * @bug 8077559
- * @summary Tests Compact String. This one is for String.compareTo.
+ * @bug 8077559 8137326
+ * @summary Tests Compact String. Verifies the compareTo method for String,
+ * StringBuilder and StringBuffer.
* @run testng/othervm -XX:+CompactStrings CompareTo
* @run testng/othervm -XX:-CompactStrings CompareTo
*/
@@ -91,4 +92,46 @@
source));
});
}
+
+ /*
+ * Runs the same test with StringBuilder
+ */
+ @Test(dataProvider = "provider")
+ public void testStringBuilder(String str, String anotherString, int expected) {
+ StringBuilder another = new StringBuilder(anotherString);
+ map.get(str)
+ .forEach(
+ (source, data) -> {
+ StringBuilder sb = new StringBuilder(data);
+ assertEquals(
+ sb.compareTo(another),
+ expected,
+ String.format(
+ "testing StringBuilder(%s).compareTo(%s), source : %s, ",
+ escapeNonASCIIs(data),
+ escapeNonASCIIs(anotherString),
+ source));
+ });
+ }
+
+ /*
+ * Runs the same test with StringBuffer
+ */
+ @Test(dataProvider = "provider")
+ public void testStringBuffer(String str, String anotherString, int expected) {
+ StringBuffer another = new StringBuffer(anotherString);
+ map.get(str)
+ .forEach(
+ (source, data) -> {
+ StringBuffer sb = new StringBuffer(data);
+ assertEquals(
+ sb.compareTo(another),
+ expected,
+ String.format(
+ "testing StringBuffer(%s).compareTo(%s), source : %s, ",
+ escapeNonASCIIs(data),
+ escapeNonASCIIs(anotherString),
+ source));
+ });
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/StringBuffer/Comparison.java Thu Mar 01 15:31:04 2018 -0800
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8137326
+ * @summary Test to verify the Comparable implementation for the StringBuffer class.
+ * @run testng Comparison
+ */
+public class Comparison {
+ static char SEP = ':';
+
+ static String[][] books = {
+ {"Biography", "Steve Jobs"},
+ {"Biography", "Elon Musk: Tesla, SpaceX, and the Quest for a Fantastic Future"},
+ {"Law", "Law 101: Everything You Need to Know About American Law, Fourth Edition"},
+ {"Law", "The Tools of Argument: How the Best Lawyers Think, Argue, and Win"},
+ {"History", "The History Book (Big Ideas Simply Explained)"},
+ {"History", "A People's History of the United States"},
+ };
+
+ /**
+ * Verifies the Comparable implementation by comparing with two TreeSet that
+ * contain either StringBuffer or String.
+ */
+ @Test
+ public void compareWithString() {
+ Set<StringBuffer> sbSet = constructSBSet();
+ Set<String> sSet = constructStringSet();
+ Iterator<StringBuffer> iSB = sbSet.iterator();
+ Iterator<String> iS = sSet.iterator();
+ while (iSB.hasNext()) {
+ String temp1 = iSB.next().toString();
+ System.out.println(temp1);
+ String temp2 = iS.next();
+ System.out.println(temp2);
+
+ Assert.assertTrue(temp1.equals(temp2), "Comparing item by item");
+ }
+
+ }
+
+ /**
+ * Compares between StringBuffers
+ */
+ @Test
+ public void testCompare() {
+ StringBuffer sb1 = generateTestBuffer(65, 70, 97, 102);
+ StringBuffer sb2 = generateTestBuffer(65, 70, 97, 102);
+ StringBuffer sb3 = generateTestBuffer(65, 71, 97, 103);
+
+ System.out.println(sb1.toString());
+ System.out.println(sb2.toString());
+ System.out.println(sb3.toString());
+ Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
+ Assert.assertFalse(sb1.compareTo(sb3) == 0, "Compare sb1 and sb3");
+ }
+
+ /**
+ * Verifies that the comparison is from index 0 to length() - 1 of the two
+ * character sequences.
+ */
+ @Test
+ public void testModifiedSequence() {
+ StringBuffer sb1 = generateTestBuffer(65, 70, 97, 102);
+ StringBuffer sb2 = generateTestBuffer(65, 70, 98, 103);
+
+ // contain different character sequences
+ Assert.assertFalse(sb1.compareTo(sb2) == 0, "Compare the sequences before truncation");
+
+ // the first 5 characters however are the same
+ sb1.setLength(5);
+ sb2.setLength(5);
+
+ System.out.println(sb1.toString());
+ System.out.println(sb2.toString());
+
+ Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
+ Assert.assertTrue(sb1.toString().compareTo(sb2.toString()) == 0, "Compare strings of sb1 and sb2");
+ }
+
+ private Set<String> constructStringSet() {
+ Set<String> sSet = new TreeSet<>();
+ for (String[] book : books) {
+ sSet.add(book[0] + SEP + book[1]);
+ }
+ return sSet;
+ }
+
+ private Set<StringBuffer> constructSBSet() {
+ Set<StringBuffer> sbSet = new TreeSet<>();
+ for (String[] book : books) {
+ sbSet.add(new StringBuffer(book[0]).append(SEP).append(book[1]));
+ }
+ return sbSet;
+ }
+
+ private static StringBuffer generateTestBuffer(int from1, int to1,
+ int from2, int to2) {
+ StringBuffer aBuffer = new StringBuffer(50);
+
+ for (int i = from1; i < to1; i++) {
+ aBuffer.append((char)i);
+ }
+ for (int i = from2; i < to2; i++) {
+ aBuffer.append((char)i);
+ }
+ return aBuffer;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/StringBuilder/Comparison.java Thu Mar 01 15:31:04 2018 -0800
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @test
+ * @bug 8137326
+ * @summary Test to verify the Comparable implementation for the StringBuilder class.
+ * @run testng Comparison
+ */
+public class Comparison {
+ static char SEP = ':';
+
+ static String[][] books = {
+ {"Biography", "Steve Jobs"},
+ {"Biography", "Elon Musk: Tesla, SpaceX, and the Quest for a Fantastic Future"},
+ {"Law", "Law 101: Everything You Need to Know About American Law, Fourth Edition"},
+ {"Law", "The Tools of Argument: How the Best Lawyers Think, Argue, and Win"},
+ {"History", "The History Book (Big Ideas Simply Explained)"},
+ {"History", "A People's History of the United States"},
+ };
+
+ /**
+ * Verifies the Comparable implementation by comparing with two TreeSet that
+ * contain either StringBuilder or String.
+ */
+ @Test
+ public void compareWithString() {
+ Set<StringBuilder> sbSet = constructSBSet();
+ Set<String> sSet = constructStringSet();
+ Iterator<StringBuilder> iSB = sbSet.iterator();
+ Iterator<String> iS = sSet.iterator();
+ while (iSB.hasNext()) {
+ String temp1 = iSB.next().toString();
+ System.out.println(temp1);
+ String temp2 = iS.next();
+ System.out.println(temp2);
+
+ Assert.assertTrue(temp1.equals(temp2), "Comparing item by item");
+ }
+
+ }
+
+ /**
+ * Compares between StringBuilders
+ */
+ @Test
+ public void testCompare() {
+ StringBuilder sb1 = generateTestBuffer(65, 70, 97, 102);
+ StringBuilder sb2 = generateTestBuffer(65, 70, 97, 102);
+ StringBuilder sb3 = generateTestBuffer(65, 71, 97, 103);
+
+ System.out.println(sb1.toString());
+ System.out.println(sb2.toString());
+ System.out.println(sb3.toString());
+ Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
+ Assert.assertFalse(sb1.compareTo(sb3) == 0, "Compare sb1 and sb3");
+ }
+
+ /**
+ * Verifies that the comparison is from index 0 to length() - 1 of the two
+ * character sequences.
+ */
+ @Test
+ public void testModifiedSequence() {
+ StringBuilder sb1 = generateTestBuffer(65, 70, 97, 102);
+ StringBuilder sb2 = generateTestBuffer(65, 70, 98, 103);
+
+ // contain different character sequences
+ Assert.assertFalse(sb1.compareTo(sb2) == 0, "Compare the sequences before truncation");
+
+ // the first 5 characters however are the same
+ sb1.setLength(5);
+ sb2.setLength(5);
+
+ System.out.println(sb1.toString());
+ System.out.println(sb2.toString());
+
+ Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
+ Assert.assertTrue(sb1.toString().compareTo(sb2.toString()) == 0, "Compare strings of sb1 and sb2");
+ }
+
+ private Set<String> constructStringSet() {
+ Set<String> sSet = new TreeSet<>();
+ for (String[] book : books) {
+ sSet.add(book[0] + SEP + book[1]);
+ }
+ return sSet;
+ }
+
+ private Set<StringBuilder> constructSBSet() {
+ Set<StringBuilder> sbSet = new TreeSet<>();
+ for (String[] book : books) {
+ sbSet.add(new StringBuilder(book[0]).append(SEP).append(book[1]));
+ }
+ return sbSet;
+ }
+
+ private static StringBuilder generateTestBuffer(int from1, int to1,
+ int from2, int to2) {
+ StringBuilder aBuffer = new StringBuilder(50);
+
+ for (int i = from1; i < to1; i++) {
+ aBuffer.append((char)i);
+ }
+ for (int i = from2; i < to2; i++) {
+ aBuffer.append((char)i);
+ }
+ return aBuffer;
+ }
+}