8137326: Methods for comparing CharSequence, StringBuilder, and StringBuffer
authorjoehw
Thu, 01 Mar 2018 15:31:04 -0800
changeset 49115 ecfaa82c53be
parent 49114 e28aba8a82df
child 49116 ef9ddc426975
8137326: Methods for comparing CharSequence, StringBuilder, and StringBuffer Reviewed-by: rriggs, smarks, sherman, tvaleev
src/java.base/share/classes/java/lang/AbstractStringBuilder.java
src/java.base/share/classes/java/lang/CharSequence.java
src/java.base/share/classes/java/lang/StringBuffer.java
src/java.base/share/classes/java/lang/StringBuilder.java
src/java.base/share/classes/java/lang/StringLatin1.java
src/java.base/share/classes/java/lang/StringUTF16.java
test/jdk/java/lang/CharSequence/Comparison.java
test/jdk/java/lang/String/CompactString/CompareTo.java
test/jdk/java/lang/StringBuffer/Comparison.java
test/jdk/java/lang/StringBuilder/Comparison.java
--- 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;
+    }
+}