title: Why is String.toUpperCase() so slow?
body: <p>This code is about 3 times faster than the standard String.toUpperCase() function:</p>
  
  <pre><code>public static String toUpperString(String pString) {
      if (pString != null) {
          char[] retChar = pString.toCharArray();
          for (int idx = 0; idx &lt; pString.length(); idx++) {
              char c = retChar[idx];
              if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') {
                  retChar[idx] = (char) (c &amp; -33);
              }
          }
          return new String(retChar);
      } else {
          return null;
      }
  }
  </code></pre>
  
  <p>Why is it so much faster? What other work is String.toUpperCase() also doing?
  In other words, are there cases in which this code will not work?</p>
  
  <p>Benchmark results for a random long string (plain text) executed 2,000,000 times:</p>
  
  <p>toUpperString(String) : 3514.339 ms - about 3.5 seconds<br>
  String.toUpperCase() : 9705.397 ms - almost 10 seconds</p>
  
  <p>** UPDATE</p>
  
  <p>I have added the "latin" check and used this as benchmark (for those who don't believe me):</p>
  
  <pre><code>public class BenchmarkUpperCase {
  
      public static String[] randomStrings;
  
      public static String nextRandomString() {
          SecureRandom random = new SecureRandom();
          return new BigInteger(500, random).toString(32);
      }
  
      public static String customToUpperString(String pString) {
          if (pString != null) {
              char[] retChar = pString.toCharArray();
              for (int idx = 0; idx &lt; pString.length(); idx++) {
                  char c = retChar[idx];
                  if (c &gt;= 'a' &amp;&amp; c &lt;= 'z') {
                      retChar[idx] = (char) (c &amp; -33);
                  } else if (c &gt;= 192) { // now catering for other than latin...
                      retChar[idx] = Character.toUpperCase(c);
                  }
              }
              return new String(retChar);
          } else {
              return null;
          }
      }
  
      public static void main(String... args) {
          long timerStart, timePeriod = 0;
          randomStrings = new String[1000];
          for (int idx = 0; idx &lt; 1000; idx++) {
              randomStrings[idx] = nextRandomString();
          }
          String dummy = null;
  
          for (int count = 1; count &lt;= 5; count++) {
              timerStart = System.nanoTime();
              for (int idx = 0; idx &lt; 20000000; idx++) {
                  dummy = randomStrings[idx % 1000].toUpperCase();
              }
              timePeriod = System.nanoTime() - timerStart;
              System.out.println(count + " String.toUpper() : " + (timePeriod / 1000000));
          }
  
          for (int count = 1; count &lt;= 5; count++) {
              timerStart = System.nanoTime();
              for (int idx = 0; idx &lt; 20000000; idx++) {
                  dummy = customToUpperString(randomStrings[idx % 1000]);
              }
              timePeriod = System.nanoTime() - timerStart;
              System.out.println(count + " customToUpperString() : " + (timePeriod / 1000000));
          }
      }
  
  }
  </code></pre>
  
  <p>I get these results:</p>
  
  <pre><code>1 String.toUpper() : 10724
  2 String.toUpper() : 10551
  3 String.toUpper() : 10551
  4 String.toUpper() : 10660
  5 String.toUpper() : 10575
  1 customToUpperString() : 6687
  2 customToUpperString() : 6684
  3 customToUpperString() : 6686
  4 customToUpperString() : 6693
  5 customToUpperString() : 6710
  </code></pre>
  
  <p>Which is still about 60% faster. </p>