Why is String.strip() 5 times faster than String.trim() for blank string In Java 11

  • A+
Category:Languages

I've encountered an interesting scenario. For some reason strip() against blank string (contains whitespaces only) significantly faster than trim() in Java 11.

Benchmark

public class Test {      public static final String TEST_STRING = "   "; // 3 whitespaces      @Benchmark     @Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS)     @Measurement(iterations = 20, time = 500, timeUnit = MILLISECONDS)     @BenchmarkMode(Mode.Throughput)     public void testTrim() {         TEST_STRING.trim();     }      @Benchmark     @Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS)     @Measurement(iterations = 20, time = 500, timeUnit = MILLISECONDS)     @BenchmarkMode(Mode.Throughput)     public void testStrip() {         TEST_STRING.strip();     }      public static void main(String[] args) throws Exception {         org.openjdk.jmh.Main.main(args);     } } 

Results

# Run complete. Total time: 00:04:16  Benchmark        Mode  Cnt           Score          Error  Units Test.testStrip  thrpt  200  2067457963.295 ± 12353310.918  ops/s Test.testTrim   thrpt  200   402307182.894 ±  4559641.554  ops/s 

Apparently strip() outperforms trim() ~5 times.

Although for non-blank string, results are almost identical:

public class Test {      public static final String TEST_STRING = " Test String ";      @Benchmark     @Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS)     @Measurement(iterations = 20, time = 500, timeUnit = MILLISECONDS)     @BenchmarkMode(Mode.Throughput)     public void testTrim() {         TEST_STRING.trim();     }      @Benchmark     @Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS)     @Measurement(iterations = 20, time = 500, timeUnit = MILLISECONDS)     @BenchmarkMode(Mode.Throughput)     public void testStrip() {         TEST_STRING.strip();     }      public static void main(String[] args) throws Exception {         org.openjdk.jmh.Main.main(args);     } }   # Run complete. Total time: 00:04:16  Benchmark        Mode  Cnt          Score         Error  Units Test.testStrip  thrpt  200  126939018.461 ± 1462665.695  ops/s Test.testTrim   thrpt  200  141868439.680 ± 1243136.707  ops/s 

How come? Is this a bug or am I doing it wrong?


Testing environment

  • CPU - Intel Xeon E3-1585L v5 @3.00 GHz
  • OS - Windows 7 SP 1 64-bit
  • JVM - Oracle JDK 11.0.1
  • Benchamrk - JMH v 1.19

 


On OpenJDK 11.0.1 String.strip() (actually StringLatin1.strip()) optimizes stripping to an empty String by returning an interned String constant:

public static String strip(byte[] value) {     int left = indexOfNonWhitespace(value);     if (left == value.length) {         return "";     } 

while String.trim() (actually StringLatin1.trim()) always allocates a new String object. In your example st = 3 and len = 3 so

return ((st > 0) || (len < value.length)) ?         newString(value, st, len - st) : null; 

will under the hood copy the array and creates a new String object

return new String(Arrays.copyOfRange(val, index, index + len),                       LATIN1); 

Making above assumption we can update the benchmark to compare against a non-empty String which shouldn't be affected by mentioned String.strip() optimization:

@Warmup(iterations = 10, time = 200, timeUnit = MILLISECONDS) @Measurement(iterations = 20, time = 500, timeUnit = MILLISECONDS) @BenchmarkMode(Mode.Throughput) public class MyBenchmark {    public static final String EMPTY_STRING = "   "; // 3 whitespaces   public static final String NOT_EMPTY_STRING = "  a "; // 3 whitespaces with a in the middle    @Benchmark   public void testEmptyTrim() {     EMPTY_STRING.trim();   }    @Benchmark   public void testEmptyStrip() {     EMPTY_STRING.strip();   }    @Benchmark   public void testNotEmptyTrim() {     NOT_EMPTY_STRING.trim();   }    @Benchmark   public void testNotEmptyStrip() {     NOT_EMPTY_STRING.strip();   }  } 

Running it shows no significant difference between strip() and trim() for a non-empty String. Oddly enough trimming to an empty String is still the slowest:

Benchmark                       Mode  Cnt           Score           Error  Units MyBenchmark.testEmptyStrip     thrpt  100  1887848947.416 ± 257906287.634  ops/s MyBenchmark.testEmptyTrim      thrpt  100   206638996.217 ±  57952310.906  ops/s MyBenchmark.testNotEmptyStrip  thrpt  100   399701777.916 ±   2429785.818  ops/s MyBenchmark.testNotEmptyTrim   thrpt  100   385144724.856 ±   3928016.232  ops/s 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: