< prev index next >

src/java.base/share/classes/java/lang/String.java

Print this page

        

@@ -27,10 +27,11 @@
 
 import java.io.ObjectStreamField;
 import java.io.UnsupportedEncodingException;
 import java.lang.annotation.Native;
 import java.lang.invoke.MethodHandles;
+import java.lang.compiler.IntrinsicCandidate;
 import java.lang.constant.Constable;
 import java.lang.constant.ConstantDesc;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;

@@ -73,11 +74,11 @@
  * Here are some more examples of how strings can be used:
  * <blockquote><pre>
  *     System.out.println("abc");
  *     String cde = "cde";
  *     System.out.println("abc" + cde);
- *     String c = "abc".substring(2, 3);
+ *     String c = "abc".substring(2,3);
  *     String d = cde.substring(1, 2);
  * </pre></blockquote>
  * <p>
  * The class {@code String} includes methods for examining
  * individual characters of the sequence, for comparing strings, for

@@ -1018,12 +1019,13 @@
         if (this == anObject) {
             return true;
         }
         if (anObject instanceof String) {
             String aString = (String)anObject;
-            if (!COMPACT_STRINGS || this.coder == aString.coder) {
-                return StringLatin1.equals(value, aString.value);
+            if (coder() == aString.coder()) {
+                return isLatin1() ? StringLatin1.equals(value, aString.value)
+                                  : StringUTF16.equals(value, aString.value);
             }
         }
         return false;
     }
 

@@ -1054,20 +1056,19 @@
         if (len != sb.length()) {
             return false;
         }
         byte v1[] = value;
         byte v2[] = sb.getValue();
-        byte coder = coder();
-        if (coder == sb.getCoder()) {
+        if (coder() == sb.getCoder()) {
             int n = v1.length;
             for (int i = 0; i < n; i++) {
                 if (v1[i] != v2[i]) {
                     return false;
                 }
             }
         } else {
-            if (coder != LATIN1) {  // utf16 str and latin1 abs can never be "equal"
+            if (!isLatin1()) {  // utf16 str and latin1 abs can never be "equal"
                 return false;
             }
             return StringUTF16.contentEquals(v1, v2, len);
         }
         return true;

@@ -1207,17 +1208,16 @@
      *          lexicographically greater than the string argument.
      */
     public int compareTo(String anotherString) {
         byte v1[] = value;
         byte v2[] = anotherString.value;
-        byte coder = coder();
-        if (coder == anotherString.coder()) {
-            return coder == LATIN1 ? StringLatin1.compareTo(v1, v2)
-                                   : StringUTF16.compareTo(v1, v2);
+        if (coder() == anotherString.coder()) {
+            return isLatin1() ? StringLatin1.compareTo(v1, v2)
+                              : StringUTF16.compareTo(v1, v2);
         }
-        return coder == LATIN1 ? StringLatin1.compareToUTF16(v1, v2)
-                               : StringUTF16.compareToLatin1(v1, v2);
+        return isLatin1() ? StringLatin1.compareToUTF16(v1, v2)
+                          : StringUTF16.compareToLatin1(v1, v2);
      }
 
     /**
      * A Comparator that orders {@code String} objects as by
      * {@code compareToIgnoreCase}. This comparator is serializable.

@@ -1237,17 +1237,16 @@
         private static final long serialVersionUID = 8575799808933029326L;
 
         public int compare(String s1, String s2) {
             byte v1[] = s1.value;
             byte v2[] = s2.value;
-            byte coder = s1.coder();
-            if (coder == s2.coder()) {
-                return coder == LATIN1 ? StringLatin1.compareToCI(v1, v2)
-                                       : StringUTF16.compareToCI(v1, v2);
+            if (s1.coder() == s2.coder()) {
+                return s1.isLatin1() ? StringLatin1.compareToCI(v1, v2)
+                                     : StringUTF16.compareToCI(v1, v2);
             }
-            return coder == LATIN1 ? StringLatin1.compareToCI_UTF16(v1, v2)
-                                   : StringUTF16.compareToCI_Latin1(v1, v2);
+            return s1.isLatin1() ? StringLatin1.compareToCI_UTF16(v1, v2)
+                                 : StringUTF16.compareToCI_Latin1(v1, v2);
         }
 
         /** Replaces the de-serialized object. */
         private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
     }

@@ -1317,12 +1316,11 @@
         if ((ooffset < 0) || (toffset < 0) ||
              (toffset > (long)length() - len) ||
              (ooffset > (long)other.length() - len)) {
             return false;
         }
-        byte coder = coder();
-        if (coder == other.coder()) {
+        if (coder() == other.coder()) {
             if (!isLatin1() && (len > 0)) {
                 toffset = toffset << 1;
                 ooffset = ooffset << 1;
                 len = len << 1;
             }

@@ -1330,11 +1328,11 @@
                 if (tv[toffset++] != ov[ooffset++]) {
                     return false;
                 }
             }
         } else {
-            if (coder == LATIN1) {
+            if (coder() == LATIN1) {
                 while (len-- > 0) {
                     if (StringLatin1.getChar(tv, toffset++) !=
                         StringUTF16.getChar(ov, ooffset++)) {
                         return false;
                     }

@@ -1412,17 +1410,16 @@
                 || (ooffset > (long)other.length() - len)) {
             return false;
         }
         byte tv[] = value;
         byte ov[] = other.value;
-        byte coder = coder();
-        if (coder == other.coder()) {
-            return coder == LATIN1
+        if (coder() == other.coder()) {
+            return isLatin1()
               ? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len)
               : StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len);
         }
-        return coder == LATIN1
+        return isLatin1()
               ? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len)
               : StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len);
     }
 
     /**

@@ -1449,20 +1446,19 @@
         }
         byte ta[] = value;
         byte pa[] = prefix.value;
         int po = 0;
         int pc = pa.length;
-        byte coder = coder();
-        if (coder == prefix.coder()) {
-            int to = (coder == LATIN1) ? toffset : toffset << 1;
+        if (coder() == prefix.coder()) {
+            int to = isLatin1() ? toffset : toffset << 1;
             while (po < pc) {
                 if (ta[to++] != pa[po++]) {
                     return false;
                 }
             }
         } else {
-            if (coder == LATIN1) {  // && pcoder == UTF16
+            if (isLatin1()) {  // && pcoder == UTF16
                 return false;
             }
             // coder == UTF16 && pcoder == LATIN1)
             while (po < pc) {
                 if (StringUTF16.getChar(ta, toffset++) != (pa[po++] & 0xff)) {

@@ -1691,16 +1687,15 @@
      * @param   str   the substring to search for.
      * @return  the index of the first occurrence of the specified substring,
      *          or {@code -1} if there is no such occurrence.
      */
     public int indexOf(String str) {
-        byte coder = coder();
-        if (coder == str.coder()) {
+        if (coder() == str.coder()) {
             return isLatin1() ? StringLatin1.indexOf(value, str.value)
                               : StringUTF16.indexOf(value, str.value);
         }
-        if (coder == LATIN1) {  // str.coder == UTF16
+        if (coder() == LATIN1) {  // str.coder == UTF16
             return -1;
         }
         return StringUTF16.indexOfLatin1(value, str.value);
     }
 

@@ -2158,52 +2153,31 @@
      * @param  replacement The replacement sequence of char values
      * @return  The resulting string
      * @since 1.5
      */
     public String replace(CharSequence target, CharSequence replacement) {
-        String trgtStr = target.toString();
+        String tgtStr = target.toString();
         String replStr = replacement.toString();
-        int thisLen = length();
-        int trgtLen = trgtStr.length();
-        int replLen = replStr.length();
-
-        if (trgtLen > 0) {
-            if (trgtLen == 1 && replLen == 1) {
-                return replace(trgtStr.charAt(0), replStr.charAt(0));
-            }
-
-            boolean thisIsLatin1 = this.isLatin1();
-            boolean trgtIsLatin1 = trgtStr.isLatin1();
-            boolean replIsLatin1 = replStr.isLatin1();
-            String ret = (thisIsLatin1 && trgtIsLatin1 && replIsLatin1)
-                    ? StringLatin1.replace(value, thisLen,
-                                           trgtStr.value, trgtLen,
-                                           replStr.value, replLen)
-                    : StringUTF16.replace(value, thisLen, thisIsLatin1,
-                                          trgtStr.value, trgtLen, trgtIsLatin1,
-                                          replStr.value, replLen, replIsLatin1);
-            if (ret != null) {
-                return ret;
-            }
+        int j = indexOf(tgtStr);
+        if (j < 0) {
             return this;
-
-        } else { // trgtLen == 0
-            int resultLen;
-            try {
-                resultLen = Math.addExact(thisLen, Math.multiplyExact(
-                        Math.addExact(thisLen, 1), replLen));
-            } catch (ArithmeticException ignored) {
-                throw new OutOfMemoryError();
-            }
-
-            StringBuilder sb = new StringBuilder(resultLen);
-            sb.append(replStr);
-            for (int i = 0; i < thisLen; ++i) {
-                sb.append(charAt(i)).append(replStr);
-            }
-            return sb.toString();
         }
+        int tgtLen = tgtStr.length();
+        int tgtLen1 = Math.max(tgtLen, 1);
+        int thisLen = length();
+
+        int newLenHint = thisLen - tgtLen + replStr.length();
+        if (newLenHint < 0) {
+            throw new OutOfMemoryError();
+        }
+        StringBuilder sb = new StringBuilder(newLenHint);
+        int i = 0;
+        do {
+            sb.append(this, i, j).append(replStr);
+            i = j + tgtLen;
+        } while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
+        return sb.append(this, i, thisLen).toString();
     }
 
     /**
      * Splits this string around matches of the given
      * <a href="../util/regex/Pattern.html#sum">regular expression</a>.

@@ -2987,10 +2961,23 @@
      * <p> The locale always used is the one returned by {@link
      * java.util.Locale#getDefault(java.util.Locale.Category)
      * Locale.getDefault(Locale.Category)} with
      * {@link java.util.Locale.Category#FORMAT FORMAT} category specified.
      *
+     * @implNote
+     * An invocation of this method may be intrinsified {@link java.lang.compiler.IntrinsicCandidate}
+     * if the {@code format} string is a constant expression. Intrinsification replaces the method
+     * invocation with a string concatenation operation. No checks are made during intrinsification
+     * on the content of the {@code format} string, so an IllegalFormatException is possible at
+     * run time.
+     * <p>
+     * The treatment of subsequent arguments is the same as without intrinsification: arguments that
+     * are constant expressions are evaluated at compile time, and arguments that are not constant
+     * expressions are evaluated at run time. (An argument that is a nested invocation of an
+     * intrinsifiable method may be evaluated at compile time and/or run time, per the compiler's
+     * usual discretion on when and how to intrinsify.)
+     *
      * @param  format
      *         A <a href="../util/Formatter.html#syntax">format string</a>
      *
      * @param  args
      *         Arguments referenced by the format specifiers in the format

@@ -3015,18 +3002,32 @@
      * @return  A formatted string
      *
      * @see  java.util.Formatter
      * @since  1.5
      */
+    @IntrinsicCandidate
     public static String format(String format, Object... args) {
         return new Formatter().format(format, args).toString();
     }
 
     /**
      * Returns a formatted string using the specified locale, format string,
      * and arguments.
      *
+     * @implNote
+     * An invocation of this method may be intrinsified {@link java.lang.compiler.IntrinsicCandidate}
+     * if the {@code format} string is a constant expression. Intrinsification replaces the method
+     * invocation with a string concatenation operation. No checks are made during intrinsification
+     * on the content of the {@code format} string, so an IllegalFormatException is possible at
+     * run time.
+     * <p>
+     * The treatment of subsequent arguments is the same as without intrinsification: arguments that
+     * are constant expressions are evaluated at compile time, and arguments that are not constant
+     * expressions are evaluated at run time. (An argument that is a nested invocation of an
+     * intrinsifiable method may be evaluated at compile time and/or run time, per the compiler's
+     * usual discretion on when and how to intrinsify.)
+     *
      * @param  l
      *         The {@linkplain java.util.Locale locale} to apply during
      *         formatting.  If {@code l} is {@code null} then no localization
      *         is applied.
      *

@@ -3056,15 +3057,124 @@
      * @return  A formatted string
      *
      * @see  java.util.Formatter
      * @since  1.5
      */
+    @IntrinsicCandidate
     public static String format(Locale l, String format, Object... args) {
         return new Formatter(l).format(format, args).toString();
     }
 
     /**
+     * Returns a formatted string using this string, as the specified
+     * <a href="../util/Formatter.html#syntax">format</a>, and
+     * arguments.
+     *
+     * <p> The locale always used is the one returned by {@link
+     * java.util.Locale#getDefault(java.util.Locale.Category)
+     * Locale.getDefault(Locale.Category)} with
+     * {@link java.util.Locale.Category#FORMAT FORMAT} category specified.
+     *
+     * @implNote
+     * An invocation of this method may be intrinsified {@link java.lang.compiler.IntrinsicCandidate}
+     * if the {@code format} string is a constant expression. Intrinsification replaces the method
+     * invocation with a string concatenation operation. No checks are made during intrinsification
+     * on the content of the {@code format} string, so an IllegalFormatException is possible at
+     * run time.
+     * <p>
+     * The treatment of subsequent arguments is the same as without intrinsification: arguments that
+     * are constant expressions are evaluated at compile time, and arguments that are not constant
+     * expressions are evaluated at run time. (An argument that is a nested invocation of an
+     * intrinsifiable method may be evaluated at compile time and/or run time, per the compiler's
+     * usual discretion on when and how to intrinsify.)
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     *
+     * @since  12
+     */
+    @IntrinsicCandidate
+    public String format(Object... args) {
+        return new Formatter().format(this, args).toString();
+    }
+
+    /**
+     * Returns a formatted string using this string, as the specified
+     * <a href="../util/Formatter.html#syntax">format</a>, the specified locale,
+     * and  arguments.
+     *
+     * @implNote
+     * An invocation of this method may be intrinsified {@link java.lang.compiler.IntrinsicCandidate}
+     * if the {@code format} string is a constant expression. Intrinsification replaces the method
+     * invocation with a string concatenation operation. No checks are made during intrinsification
+     * on the content of the {@code format} string, so an IllegalFormatException is possible at
+     * run time.
+     * <p>
+     * The treatment of subsequent arguments is the same as without intrinsification: arguments that
+     * are constant expressions are evaluated at compile time, and arguments that are not constant
+     * expressions are evaluated at run time. (An argument that is a nested invocation of an
+     * intrinsifiable method may be evaluated at compile time and/or run time, per the compiler's
+     * usual discretion on when and how to intrinsify.)
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the
+     *         <a href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     *
+     * @since  12
+     */
+    @IntrinsicCandidate
+    public String format(Locale l, Object... args) {
+        return new Formatter(l).format(this, args).toString();
+    }
+
+    /**
      * Returns the string representation of the {@code Object} argument.
      *
      * @param   obj   an {@code Object}.
      * @return  if the argument is {@code null}, then a string equal to
      *          {@code "null"}; otherwise, the value of
< prev index next >