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.14.0</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>31.0.1-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.