String Utilities in Google Guava

Introduction

Google Guava is a Java library belonging to the Guava project of Google. It has a lot of support on various areas like collections, caching, concurrency, string processing, I/O etc. These libraries help us to simplify our (Programmers) job. In this post, we will look at the String Utilities in Google Guava library – specifically we will look at the Strings class and the Splitter class.

Getting Google Guava

Google guava library is available in Maven central. Thus, for Maven projects, you can depend on it by adding the below snippet in your pom.xml.

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

For gradle, use

implementation 'com.google.guava:guava:28.0-jre'

Note: 28.0-jre is the latest version as of writing this. You can find the current latest version from the Google Guava’s Maven artifact page.

Why depend on Google Guava

Google Guava offers library methods (mostly static utility methods) as utility methods. These solve several repeated tasks done by the developers. Thus, it reduces the probability of us introducing a bug if we are to do it ourselves. 

One String utility method it offers is commonPrefix. It takes in two strings and returns the common prefix between the two Strings (abcd and abef returns ab). 
Now, you can imagine facing such a requirement in your application code and writing the code for doing this yourselves. It takes a non-trivial amount of effort for achieving this. The probability of your code having a bug in the implementation is not that low; especially in handling the edge cases. One such edge case we can think of when working with Strings are unicode characters. The implementation provided by the library takes care of handing them properly.

It is important to be aware of the functionalities offered by Google Guava. When a piece of functionality we need is available as a utility method, we must strive to use them rather than trying to solve it ourselves. 
Advantages are:
  • Someone else already tested thoroughly it.
  • Wide range of test cases are already existing as part of Google Guava to test the utilities’ implementation. If you are to write it, you also have to take care of writing and maintaining extensible tests for them. Your motive should be to focus on your prime business logic and not in (re)writing these utilities.

String Utilities

Google Guava has a lot of utility methods which cannot be covered in one post. In this post, we will look at a couple of classes.

  • Strings – It has utility methods for String and CharSequence instances.
  • Splitter – It is used to split a string into non-overlapping subsequences based on a separator.

Strings

nullToEmpty, emptyToNull and isNullOrEmpty

nullToEmpty – It returns an empty string (“”) if the passed string is null; otherwise returns the passed string as it is.
emptyToNull – It does the inverse of nullToEmpty. It returns null if passed an empty string; returns the original string otherwise.
isNullOrEmpty – Returns true if the passed string is null or empty.

System.out.println(Strings.nullToEmpty("name")); //name
System.out.println(Strings.nullToEmpty("")); //""
System.out.println(Strings.nullToEmpty(null)); //""
System.out.println(Strings.nullToEmpty(null).isEmpty()); //true

System.out.println(Strings.emptyToNull("name")); //name
System.out.println(Strings.emptyToNull(null)); //null
System.out.println(Strings.emptyToNull("")); //null

System.out.println(Strings.isNullOrEmpty("name")); //false
System.out.println(Strings.isNullOrEmpty("")); //true
System.out.println(Strings.isNullOrEmpty(null)); //true

padStart, padEnd

This method takes three parameters – the input string, the min length and the character to be padded. It prepends the character to the start of the input string as many times as needed to make the input string’s length equal to the passed min length.

System.out.println(Strings.padStart("7001", 6, '0')); //007001
System.out.println(Strings.padStart("123456", 6, '0')); //123456

In the first case, it padded 0 two times so that the final string length is equal to the passed min length (6). In the second case, the input string itself is of the required min length and hence no padding was done.

padEnd is a similar method which pads the character at the end rather than at the beginning.

System.out.println(Strings.padEnd("7001", 6, '0')); //700100
System.out.println(Strings.padEnd("123456", 6, '0')); //123456

repeat

It takes a string and a count. It returns a string consisting of the original string repeated the ‘count’ number of times.

System.out.println(Strings.repeat("abc", 3));//abcabcabc

commonPrefix and commonSuffix

commonPrefix returns the largest common prefix between two strings and commonSuffix returns the largest common suffix between two strings.

System.out.println(Strings.commonPrefix("abcdef", "abqef"));//ab
System.out.println(Strings.commonSuffix("abcdef", "abqef"));//ef

Splitter

The methods in the Splitter class is used to split a string into substrings based on the provided delimiter.We can obtain a Splitter instance by passing a delimiter. Once we have a Splitter, we can split a string based on how the Splitter is configured. 

Iterable<String> result = Splitter.on(",")
    .split("a,b,c");
System.out.println(result);//[a, b, c]

The above Splitter is configured to split strings by comma. Thus it splits the string “a,b,c” into an Iterable<String> which gives [a, b, c] when iterated upon.

Obtaining Splitter instances

on and onPattern

We will now look at the various ways to obtain a Splitter. There are various overloads of Splitter.on methods that take a character, String or a Pattern as delimiters. We can also pass a Pattern as a string to the onPattern method.

Splitter commaSplitter = Splitter.on(','); //seen earlier

Splitter wordSplitter = Splitter.on("::");
System.out.println(wordSplitter.split("the::text::is::separated::by::double::colon")); 
//prints [the, text, is, separated, by, double, colon]

Splitter patternBasedSplitter = Splitter.on(Pattern.compile("\\s+"));
System.out.println(patternBasedSplitter.split("abc   def ghi")); //[abc, def, ghi]

System.out.println(Splitter.onPattern("\\s+").split("abc   def ghi")); //[abc, def, ghi]

fixedLength

One of the most useful methods is to split a string into equal parts of a given length. Note that the last part can be smaller than the given length.

Splitter fixedLengthSplitter = Splitter.fixedLength(3);
System.out.println(fixedLengthSplitter.split("abcdefghi")); //[abc, def, ghi]
System.out.println(fixedLengthSplitter.split("abcdefgh")); //[abc, def, gh]

Modifiers

There are a few modifier methods that can be called on a Splitter that changes or modifies the Splitter behaviour.

trimResults:
The resulting Splitter removes leading and trailing whitespaces from the resultant Strings.

System.out.println(commaSplitter.split("a, b, c")); //[a,  b,  c]

Splitter commaSplitterWithTrim = commaSplitter
                .trimResults();
System.out.println(commaSplitterWithTrim.split("a, b, c")); //[a, b, c]

Note that the first split’s result has a leading space before the strings “b” and “c”. When used trimResults, those leading spaces are trimmed.

omitEmptyStrings:
It omits any empty strings from the results.

System.out.println(commaSplitter.split("a,,b,c")); //[a, , b, c]

Splitter commaSplitterWithNoEmptyString = commaSplitter
                .omitEmptyStrings();
System.out.println(commaSplitterWithNoEmptyString.split("a,,b,c")); //[a, b, c]

The commaSplitterWithNoEmptyString removes empty strings from the output.

limit:
It returns a Splitter that is equivalent to the original Splitter but it stops splitting after the specified limit is reached. In other words, the limit we pass specifies that maximum number of items to be present in the result.Note: When omitting empty strings, the omitted strings do not count.

Splitter limitingCommaSplitter = commaSplitter.limit(3);
System.out.println(limitingCommaSplitter.split("a,b,c,d,e,f")); //[a, b, c,d,e,f]

The result has three strings “a”, “b” and “c,d,e,f”.

Important note:
The Splitter instances are immutable. Thus calling any of the modifier methods returns a new Splitter and does not modify/mutate the original splitter.

Splitter splitter = Splitter.on('/');
splitter.trimResults(); // does nothing!

splitter = splitter.trimResults(); // the returned splitter to be assigned

Wondering what are the benefits of making a class immutable and how to make a class immutable? Check out my previous posts on Benefits of Immutable class in Java and How to make a class immutable in Java.

splitToList

So, far we have used the split method. It returns an Iterable<String>. The splitToList method returns a List<String>. Since the split method returns an Iterable, it is lazy.

System.out.println(limitingCommaSplitter.splitToList("a,b,c,d,e,f")); //[a, b, c,d,e,f]

Map splitter

MapSplitter is an object that splits strings into maps. We can obtain a MapSplitter from a Splitter by using the withKeyValueSeparator method.The withKeyValueSeparator method takes a String, a char or a Splitter itself.
First, the string is split into entries based on the original Splitter. Next, the individual entries are split into key-value pairs (or map entries) using the delimiter passed to the withKeyValueSeparator method.

Splitter commaSplitter = Splitter.on(',');
Splitter.MapSplitter keyValueSplitter = commaSplitter.withKeyValueSeparator('=');
Map<String, String> map = keyValueSplitter.split("a=b,c=d");
System.out.println(map); //{a=b, c=d}

The result map has two entries as shown above.
If we had specified any modifiers on the original splitter, they it applies only to that Splitter and not to MapSplitter.

Splitter original = Splitter.on(",")
                .trimResults();
keyValueSplitter = original.withKeyValueSeparator('=');
System.out.println(keyValueSplitter.split("a=b,     c=    d")); //{a=b, c=    d}

The trimResults applies only to the original Splitter. Hence the space at the start of “c” has been trimmed (when splitting original string). But the space at the start of “d” is not trimmed (when splitting into key-values).

Important Note: The MapSplitter class is marked as @Beta which means the class and the methods related to MapSplitter is experimental and can either change (in a breaking way) or can even be removed in the future.

Conclusion

In this post, we looked at what Google Guava library is along with the benefits of using it in our project or application. We saw how to import it into our application. Then we saw about the String utilities in Google Guava library – the Strings and the Splitter classes.

References

Leave a Reply