Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

The method String.trim() removes trailing and leading whitespace. But, there's no support for just doing an L-Trim or R-Trim.

In this tutorial, we'll see a few ways that we can implement this; in the end, we'll compare their performance.

2. while Loop

The simplest solution is to go through the string using a couple of while loops.

For L-Trim, we'll read the string from left to right until we run into a non-whitespace character:

int i = 0;
while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
    i++;
}
String ltrim = s.substring(i);

ltrim is then a substring starting at the first non-whitespace character.

Or for R-Trim, we'll read our string from right to left until we run into a non-whitespace character:

int i = s.length()-1;
while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
    i--;
}
String rtrim = s.substring(0,i+1);

rtrim is then a substring starting at the beginning and ending at the first non-whitespace character.

3. String.replaceAll Using Regular Expressions

Another option is to use String.replaceAll() and a regular expression:

String ltrim = src.replaceAll("^\\s+", "");
String rtrim = src.replaceAll("\\s+$", "");

(\\s+) is the regex that matches one or many whitespace characters. The caret (^) and the ($) at the beginning and at the end of the regular expression match the beginning and the end of a line.

4. Pattern.compile() and .matcher()

We can reuse regular expressions with java.util.regex.Pattern, too:

private static Pattern LTRIM = Pattern.compile("^\\s+");
private static Pattern RTRIM = Pattern.compile("\\s+$");

String ltrim = LTRIM.matcher(s).replaceAll("");
String rtim = RTRIM.matcher(s).replaceAll("");

5. Apache Commons

Additionally, we can take advantage of the Apache Commons StringUtils#stripStart and #stripEnd methods to remove whitespace.

For that, let's first add the commons-lang3 dependency:

<dependency> 
    <groupId>org.apache.commons</groupId> 
    <artifactId>commons-lang3</artifactId> 
    <version>3.8.1</version> 
</dependency>

Following the documentation, we use null in order to strip the whitespace:

String ltrim = StringUtils.stripStart(src, null);
String rtrim = StringUtils.stripEnd(src, null);

6. Guava

Finally, we'll take advantage of Guava CharMatcher#trimLeadingFrom and #trimTrailingFrom methods to obtain the same result.

Again, let's add the appropriate Maven dependency, this time its guava:

<dependency> 
    <groupId>com.google.guava</groupId> 
    <artifactId>guava</artifactId> 
    <version>28.2-jre</version> 
</dependency>

And in Guava, it's quite similar to how it's done in Apache Commons, just with more targeted methods:

String ltrim = CharMatcher.whitespace().trimLeadingFrom(s); 
String rtrim = CharMatcher.whitespace().trimTrailingFrom(s);

7. Performance Comparison

Let's see the performance of the methods. As usual, we will make use of the open-source framework Java Microbenchmark Harness (JMH) to compare the different alternatives in nanoseconds.

7.1. Benchmark Setup

For the initial configuration of the benchmark, we've used five forks and average time calculation times in nanoseconds:

@Fork(5)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)

In the setup method, we're initializing the original message field and the resulting string to compare with:

@Setup
public void setup() {
    src = "       White spaces left and right          ";
    ltrimResult = "White spaces left and right          ";
    rtrimResult = "       White spaces left and right";
}

All the benchmarks first remove the left whitespace, then remove the right whitespace, and finally compare that the results to their expected strings.

7.2. while Loop

For our first benchmark, let's use the while loop approach:

@Benchmark
public boolean whileCharacters() {
    String ltrim = whileLtrim(src);
    String rtrim = whileRtrim(src);
    return checkStrings(ltrim, rtrim);
}

7.3. String.replaceAll() with Regular Expression

Then, let's try String.replaceAll():

@Benchmark
public boolean replaceAllRegularExpression() {
    String ltrim = src.replaceAll("^\\s+", "");
    String rtrim = src.replaceAll("\\s+$", "");
    return checkStrings(ltrim, rtrim);
}

7.4. Pattern.compile().matches()

After that comes Pattern.compile().matches():

@Benchmark
public boolean patternMatchesLTtrimRTrim() {
    String ltrim = patternLtrim(src);
    String rtrim = patternRtrim(src);
    return checkStrings(ltrim, rtrim);
}

7.5. Apache Commons

Fourth, Apache Commons:

@Benchmark
public boolean apacheCommonsStringUtils() {
    String ltrim = StringUtils.stripStart(src, " ");
    String rtrim = StringUtils.stripEnd(src, " ");
    return checkStrings(ltrim, rtrim);
}

7.6. Guava

And finally, let's use Guava:

@Benchmark
public boolean guavaCharMatcher() {
    String ltrim = CharMatcher.whitespace().trimLeadingFrom(src);
    String rtrim = CharMatcher.whitespace().trimTrailingFrom(src);
    return checkStrings(ltrim, rtrim);
}

7.7. Analysis of the Results

And we should get some results similar to the following:

# Run complete. Total time: 00:16:57

Benchmark                               Mode  Cnt     Score    Error  Units
LTrimRTrim.apacheCommonsStringUtils     avgt  100   108,718 ±  4,503  ns/op
LTrimRTrim.guavaCharMatcher             avgt  100   113,601 ±  5,563  ns/op
LTrimRTrim.patternMatchesLTtrimRTrim    avgt  100   850,085 ± 17,578  ns/op
LTrimRTrim.replaceAllRegularExpression  avgt  100  1046,660 ±  7,151  ns/op
LTrimRTrim.whileCharacters              avgt  100   110,379 ±  1,032  ns/op

And it looks like our winners are the while loop, Apache Commons, and Guava!

8. Conclusion

In this tutorial, we looked at a few different ways to remove whitespace characters at the beginning and at the end of a String.

We used while loop, String.replaceAll(), Pattern.matcher().replaceAll(), Apache Commons and Guava to obtain this result.

As always, the code is available over on GitHub.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!