Having fun with Guava’s String Helpers

Having fun with Guava’s String Helpers

During my life so far with Java I found myself often using separated Strings, such as a comma separated String. The reason is simple. Separated Strings are useful in many situations, like persistence prototyping, where you don’t want to add a full blown persistence solution but a small, lightweight file based store to save some values. Or, when you transmit data over the wire and don’t want to use a formal protocol but send just a comma separated String of values. I bet you’ve found yourself implementing a List<String> to comma separated String method at least once ;).

Whenever I used separated Strings, two things bugged me. The first is what I call the “Special Element Handling”. When transforming a collection into a separated String you always have to handle one item uniquely, for example, removing the comma from the last element. The second annoying thing is the formatting. With this I mean the special handling for whitespace or null elements in the collection.

The problem here is that the code that will be created to cover the two issues is everything but clean. Let’s take a look at a simple List to Comma Separated String method.

<pre lang="java">
public static String toCommaSeparatedString( List<String> strings ) {
  String result = "";
  if( strings != null && !strings.isEmpty() ) {
    StringBuilder stringBuilder = new StringBuilder();
    for( int i = 0; i < strings.size(); i++ ) {
      String string = strings.get( i );
      if( string != null ) {
        stringBuilder.append( string );
        stringBuilder.append( "," );
      }
    }
    stringBuilder.deleteCharAt( stringBuilder.length() - 1 );
    result = stringBuilder.toString();
  }
  return result;
}
</pre>

As you can see, we handled the last element by removing the comma from the StringBuilder after the loop. We skipped null elements to avoid NPEs and mal-formatting. We also added a special flow when the collection is null or empty. Ugly, right? When converting a comma separated string back to a List we also have to handle whitespaces like those in this method:

<pre lang="java">
public static List<String> fromCommaSeparatedString( String string ) {
  List<String> strings = new ArrayList<String>();
  String[] splitted = string.split( "," );
  for( int i = 0; i < splitted.length; i++ ) {
    String element = splitted[ i ].trim();
    strings.add( element );
  }
  return strings;
}
</pre>

As I said in the beginning, everything but clean! The methods are too long and they do too many things. Also it’s not clear why we removed the last comma from the StringBuilder without understanding that we added a comma in every iteration within the loop. The good news is that Google Guava provides String Helpers. I converted the two snippets above using Guava’s Splitter and Joiner.

<pre lang="java">
public static String toCommaSeparatedString( List<String> strings ) {
  Joiner joiner = Joiner.on( "," ).skipNulls();
  return joiner.join( strings );
}

public static List<String> fromCommaSeparatedString( String string ) {
  Iterable<String> split = Splitter.on( "," ).omitEmptyStrings().trimResults().split( string );
  return Lists.newArrayList( split );
}
</pre>

With this solution we can shrink the lines of code from 22 to 9 while improving readability. The formatting problem I mentioned is also covered by methods like trimResults or skipNulls. In a nutshell, it’s a much cleaner solution compared to the first two methods ;). I have to mention that this post only covers Splitter and Joiner but there is more useful stuff related to strings in Guava. As always, feel free to disagree in a comment ;).

<a href="https://twitter.com/hstaudacher"><img title="Follow @hstaudacher" src="https://download.eclipsesource.com/~hstaudacher/followme.png" alt="" width="191" height="58" border="0" /></a>

7 Comments
  • wrm
    Posted at 12:53, 2012-07-26

    the first example looks like it will crash if a list with a null-string is given. just mentioning because the example seems to take care in checking this and that…

  • shamaz
    Posted at 15:05, 2012-07-26

    Nice. There’s also StringUtils.join from jakarta commons since a long time. It avoid creating a object instance (static method), but I agree this is less configurable.

  • Aaron Digulla
    Posted at 15:29, 2012-07-26

    Another reason is that String.split() doesn’t do what you expect when there are empty elements at the end of the list: Those are swallowed unless you use String.split(“…”, -1)

  • Bananeweizen
    Posted at 14:01, 2012-07-27

    Did I understand it right from the documentation that all of the method calls in Splitter.on( “,” ).omitEmptyStrings().trimResults() create a new Splitter object (that is 3 objects here)? If so, I feel like I still want to use the StringUtils from Apache commons for projects on mobile devices, where object allocation is often costly.

  • Danny
    Posted at 21:46, 2012-07-27

    It’s pretty common place for a builder to work this way. Most of Guava’s code of this nature is designed to be used in a ‘statis final’ configuration, which would be ideal in a mobile environment as well. That is, ‘Splitter’ is not a drop-in replacement for commons’ StringUtils.split(), but your already-configured instance is.

    Think about your use cases. Your application likely only has one or two ways it joins/splits strings. If you set the appropriate instances as constants, the intermediately produced Splitter/Joiner instances will be garbage collected early in application startup, leaving a small, thread-safe, pre-configured splitter/joiner ready for use throughout your entire application.

  • Robert Konigsberg
    Posted at 04:47, 2012-07-29

    Disagree? No way. Guava’s String utilities are outstanding: https://konigsberg.blogspot.com/2009/11/java-puzzler-splitting-hairs.html