Exploring Google Guava

Exploring Google Guava

By Dan Lewis, OCI Senior Software Engineer

April 2010


Google recently announced the public availability of Guava, a Java utility library previously available only internally at Google. Guava provides building blocks that build on the existing Java libraries and result in productivity aids for Java programmers. Guava also serves as an example of good Java coding idioms. Guava subsumes the Google Collections library and adds additional packages covering general-purpose utilities, input/output, primitives, and concurrency. My previous Java News Brief articles about Google Collections are listed in the references section at the end of this article. This article will cover almost every Class and Interface added to Google Guava since the Google Collections 1.0 release in a "definition list" format, grouped by package. Selected classes are utilized in demonstration examples. Because Google Guava, as of this writing, is distributed via Subversion repository access only, instructions are included at the end of the article for obtaining and building your own copy.

The Guava Packages

There are six Java packages in the Guava library:

1. com.google.common.annotations
annotations used by the other packages
2. com.google.common.base
common code used by the other packages, including all of the former Google Collections Library and some additional classes
3. com.google.common.collect
extensions of the Java collections framework, including all of the former Google Collections library and some additional classes
4. com.google.common.io
utility classes used for easing input/output
5. com.google.common.primitives
utility classes used when working with Java primitive types
6. com.google.common.util.concurrent
utility classes used when doing concurrent programming

Guava Package 2: com.google.common.base

This package was included with Google Collections 1.0. Since that release, the following classes, interfaces, and enums are new:

This enum defines and converts between some naming conventions commonly used in Java and C++ source code: LOWER_HYPHEN, LOWER_UNDERSCORE, LOWER_CAMEL, UPPER_CAMEL, and UPPER_UNDERSCORE
Matches primitive chars and CharSequence objects. This is used heavily in the Splitter class described later.
Provides constant definitions for the standard Charset objects, so you don't need to use String constants in your code to obtain them anymore.
Contains default values for built-in Java types.
This interface generalizes the concept of a service that can be started and stopped via asynchronous method calls and whose state can be inspected in a thread-safe way.
This class is a utility class for splitting Strings based on various conditions, the natural complement to Joiner from Google Collections and the spiritual successor to strtok() and StringTokenizer. In the example below, observe that I start with the static method on() and then call "builder" methods to get the Splitter we want before finally calling split(). I use the trimResults() and omitEmptyStrings() builder options to obtain the desired results.
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.base.Splitter;
  5. public class ExerciseSplitter {
  6. public static void main(String[] args) {
  7. final String input = "Alpha, Bravo,,Charlie ,Delta,Echo";
  8. printWords(Splitter.on(',').split(input));
  9. System.out.println();
  10. printWords(Splitter.on(',').trimResults().split(input));
  11. System.out.println();
  12. printWords(Splitter.on(',').trimResults().omitEmptyStrings().split(input));
  13. }
  15. private static void printWords(Iterable<String> words) {
  16. for (String word : words) {
  17. System.out.printf("[%s]\n", word);
  18. }
  19. }
  20. }

And the output is:

[ Bravo]
[Charlie ]
This is a utility class that contains static methods for dealing with Exceptions (Throwables).

The propagate() method (demonstrated below) will throw the argument Throwable unchanged if it is unchecked (i.e. RuntimeException or Error) or wrap it in a RuntimeException and throw it. This is useful if you are doing several operations that might throw exceptions but do not want to force callers to deal with checked exceptions.
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.base.Throwables;
  5. import java.io.InputStream;
  6. import java.net.URL;
  8. public class ExerciseThrowables {
  9. public static void main(String[] args) {
  10. try {
  11. URL url = new URL("http://ociweb.com");
  12. final InputStream in = url.openStream();
  13. // read from the input stream
  14. in.close();
  15. } catch (Throwable t) {
  16. throw Throwables.propagate(t);
  17. }
  18. }
  19. }

Guava Package 3: com.google.common.collect

This package was included with Google Collections 1.0. Since that release, the following classes and interfaces are new:

This is a utility class that is helpful for implementing the Comparable interface, e.g., the compareTo() method.

Recall that compareTo() contractually returns -1, 0, +1 as the argument is "less", "equal", or "greater" than "this".
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.collect.ComparisonChain;
  4. import com.google.common.collect.Sets;
  6. import java.util.Set;
  8. public class ExerciseComparisonChain {
  10. static class Person implements Comparable {
  11. private int birthMonth;
  12. private int birthDayOfWeek;
  13. private int birthYear;
  14. private String firstName;
  16. Person(String firstName, int birthMonth, int birthDayOfWeek, int birthYear) {
  17. this.birthMonth = birthMonth;
  18. this.birthDayOfWeek = birthDayOfWeek;
  19. this.birthYear = birthYear;
  20. this.firstName = firstName;
  21. }
  23. public int compareTo(Object o) {
  24. Person other = (Person) o;
  25. return ComparisonChain.start().
  26. compare(birthYear, other.birthYear).
  27. compare(birthMonth, other.birthMonth).
  28. compare(birthDayOfWeek, other.birthDayOfWeek).
  29. compare(firstName, other.firstName).
  30. result();
  31. }
  32. }
  34. public static void main(String[] args) {
  35. Set<Person> people = Sets.newTreeSet();
  36. people.add(new Person("Abigail", 4, 1, 1980));
  37. people.add(new Person("Courtney", 5, 2, 1981));
  38. people.add(new Person("Chastity", 5, 2, 1981));
  39. for (Person person : people) {
  40. System.out.println(person.firstName);
  41. }
  42. }
  43. }

And the output is:

This class is used internally by ImmutableCollection.asList()
This class is used internally by ImmutableSortedSet.asList()
This class is created by calling Ordering.lexicographical(). According to the Javadocs, it returns the "dictionary" ordering. Note that to use it, you need two lists, not one list of Strings.
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.base.Joiner;
  4. import com.google.common.collect.Lists;
  5. import com.google.common.collect.Ordering;
  7. import java.util.Collections;
  8. import java.util.List;
  10. public class ExerciseLexicographicalOrdering {
  11. public static void main(String[] args) {
  12. List<String> names1 = Lists.newArrayList("whiskey", "tango", "golf");
  13. List<String> names2 = Lists.newArrayList("whiskey", "tango", "foxtrot");
  14. List<Iterable<String>> namesListList = Lists.newArrayList();
  15. namesListList.add(names1);
  16. namesListList.add(names2);
  18. final Ordering<Iterable<String>> lexOrd = Ordering.<String>natural().lexicographical();
  20. Collections.sort(namesListList, lexOrd);
  22. System.out.println(Joiner.on(',').join(namesListList));
  24. }
  25. }

And the output is:

[whiskey, tango, foxtrot],[whiskey, tango, golf]

Guava Package 4: com.google.common.io

This package wasn't part of Google Collections 1.0, so it is new to Guava. It contains the following classes and interfaces:

This Writer wraps an Appendable. This is more flexible than StringWriter included with the JDK.
This interface extends the java.io.DataInput interface, but the methods don't throw IOException. See static method ByteStreams.newDataInput().
This interface extends the java.io.DataOutput interface, but the methods don't throwIOException. See static method ByteStreams.newDataOutput().
This interface is a callback expected by Files.readBytes(). Implement processBytes() to process bytes as they are received. Return true to continue processing or false otherwise. The Files class is described later.
Utility methods for reading, writing, copying, joining, and hashing InputStreams and OutputStreams (binary data).
Utility methods for reading, writing, copying, joining, and hashing Readers and Writers (character data).
Utility methods for closing Closeables (e.g. Streams, Files, etc). In the example below,closeQuietly() is used to close the OutputStream and log any exceptions encountered to a java.util.logging.Logger.
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.base.Throwables;
  4. import com.google.common.io.Closeables;
  6. import java.io.File;
  7. import java.io.FileOutputStream;
  8. import java.io.IOException;
  9. import java.io.OutputStream;
  11. public class ExerciseCloseables {
  12. public static void main(String[] args) {
  13. final OutputStream outputStream = newTempFileOutputStream();
  14. Closeables.closeQuietly(outputStream);
  15. }
  17. private static OutputStream newTempFileOutputStream() {
  18. try {
  19. final File tmpFile = File.createTempFile(ExerciseCloseables.class.getName(), "tmp");
  20. return new FileOutputStream(tmpFile);
  21. } catch (IOException e) {
  22. throw Throwables.propagate(e);
  23. }
  24. }
  25. }
InputStream that provides a getCount() method that returns number of bytes read as a long.
OutputStream that provides a getCount() method that returns number of bytes read as a long.
From the Javadocs: "An OutputStream that starts buffering to a byte array, but switches to file buffering once the data reaches a configurable size."
Utility methods for reading from, writing to, and manipulating files and directories.
Utility method for flushing Flushables (e.g. Streams, Files, etc).
This parameterized interface is returned by several static utility methods in Files, ByteStreams, CharStreams, and Resources. Parameter T is usually an InputStream or Reader(or subclass).
This InputStream descendant is constructed with an integer that limits the maximum number of bytes that can be read. Attempting to read beyond returns -1, which typically means end of stream.
This class is an implementation detail of LineReader.
This interface is a callback passed as argument to CharStreams.readlines(),Files.readLines(), and Resources.readLines(). The processLine() method is called back for each line, and you should return false to stop processing. Finally, getResult() may be called to return the result of processing all the lines. The type of the return is type parameter T.
This is a more flexible version of BufferedReader that works for all implementers ofReadable, not just Reader. For example, java.io.CharBuffer subclasses are supported.
This class is used internally by ByteStreams.join() which allows multiple InputStreams to be "concatenated" or read serially, one after the other, as if they were one stream.
This class is used internally by CharStreams.join() which allows multiple Readers to be "concatenated" or read serially, one after the other, as if they were one reader.
This OutputStream subclass ignores all bytes. i.e. the "bit bucket".
This parameterized interface is returned by several static utility methods in Files, ByteStreams, CharStreams, and Resources. Parameter T is usually an OutputStream or Writer (or subclass).
This implementation of java.io.FilenameFilter uses a regular expression (passed to constructor) to filter files.
The static utility methods in this class are useful for reading "Resources", or various non-code files that may be bundled with an application, e.g. data files, images, etc.

Guava Package 5: com.google.common.primitives

This package wasn't part of Google Collections 1.0 so is new to Guava. It contains the following classes and interfaces:

These classes provides static utility methods for manipulating individual primitives as well as primitives arrays, including searching, concatenating, wrapping and unwrapping. For the integral types (int, short, char byte) there are checkedCast and saturatedCast methods in the integral types that will convert a long to the given type. checkedCast will throw an exception if the long is too large or too small, but saturatedCast will return the closest value.
This class converts between primitive and wrapper meta-classes.
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.primitives.Primitives;
  5. public class ExercisePrimitives {
  6. public static void main(String[] args) {
  7. System.out.println(Primitives.isWrapperType(Integer.class));
  8. System.out.println(Primitives.isWrapperType(int.class));
  9. final Class<Integer> clazz = Integer.class;
  10. System.out.println(clazz);
  11. final Class<Integer> unwrapped = Primitives.unwrap(clazz);
  12. System.out.println(unwrapped);
  13. final Class<Integer> unwrappedTwice = Primitives.unwrap(unwrapped);
  14. System.out.println(unwrappedTwice);
  15. final Class<Integer> rewrapped = Primitives.wrap(unwrappedTwice);
  16. System.out.println(rewrapped);
  17. }
  18. }

And the output is:

class java.lang.Integer
class java.lang.Integer

Guava Package 6: com.google.common.util.concurrent

This package wasn't part of Google Collections 1.0, so it is new to Guava. It contains the following classes and interfaces:

This class wraps a Future, provided in the constructor, with the checkedGet methods specified in CheckedFuture.

To extend this class you need to implement the mapException method that translates each of the three exceptions: InterruptedExceptionCancellationException, and ExecutionException.

Consider the following example that always maps all exceptions to CustomException:
  1. package com.ociweb.jnb.apr2010;
  3. import com.google.common.util.concurrent.AbstractCheckedFuture;
  4. import com.google.common.util.concurrent.Futures;
  5. import com.google.common.util.concurrent.ListenableFuture;
  7. import java.util.concurrent.*;
  9. public class ExerciseAbstractCheckedFuture<V> extends AbstractCheckedFuture<V,
  10. ExerciseAbstractCheckedFuture.CustomException> {
  12. public ExerciseAbstractCheckedFuture(ListenableFuture<V> delegate) {
  13. super(delegate);
  14. }
  16. @Override
  17. protected CustomException mapException(Exception e) {
  18. return new CustomException(e);
  19. }
  21. public static class CustomException extends Exception {
  22. public CustomException(Throwable cause) {
  23. super(cause);
  24. }
  25. }
  27. public static void main(String[] args) {
  28. final Callable<Long> callable = new Callable<Long>() {
  29. public Long call() throws Exception {
  30. if (System.currentTimeMillis() % 2 == 0) {
  31. throw new RuntimeException();
  32. }
  33. return 100L;
  34. }
  35. };
  36. final ExecutorService executorService = Executors.newSingleThreadExecutor();
  37. final Future<Long> future = executorService.submit(callable);
  38. final ExerciseAbstractCheckedFuture<Long> checkedFuture =
  39. new ExerciseAbstractCheckedFuture<Long>(Futures.makeListenable(future));
  40. try {
  41. final long value = checkedFuture.checkedGet();
  42. System.out.println("value=" + value);
  43. } catch (CustomException e) {
  44. e.printStackTrace();
  45. }
  46. executorService.shutdown();
  47. }
  48. }

And the output is sometimes:


But other times it's a nasty stack trace starting with our CustomException.

This abstract class would be a good starting point for building a custom threaded service. At a minimum, override the run method.
This abstract class provides a starting point to implement a Future that is not based on Runnables. You simply override get() and you are on your way, with thread safety built-in.
This abstract class can be used to implement services that do something on startup and shutdown, but otherwise don't do anything.
This is a base class that can be used to create a Future that also implements the ListenableFuture interface. See the Futures.makeListenable() utility method.
This is a base class that can be used to create a Service by implementing doStart() and doStop().
This class contains static utility methods for working with Callables. So far, the only method available is returning(), which always returns the same value immediately.
This sub-interface of ListenableFuture adds two getChecked() methods that return an Exception subclass of the parameterized type E. It also, through ListenableFuture supports notification when the value is available.
This implementation of ThreadFactory wraps a given ThreadFactory, then uses it to create threads, but before returning those threads calls setDaemon(true) on them.
This class pairs Runnables with Executors for later execution. This class is used by the implementations of ListenableFuture interface in Guava but is public for broader use.
This class contains static utility methods mostly pertaining to ThreadPoolExecutors and their behavior during JVM shutdown. sameThreadExecutor() creates an ExecutorService that runs all tasks in the same thread as execute and submit(). daemonThreadFactory()and variant can be used to create daemon threads.
This is an implementation of TimeLimiter interface used for unit testing.
This interface is implemented within Futures.makeListenable() to convert any Future into a ListenableFuture.
This Service delegates to another service. Was apparently used in an earlier iteration of Guava but not used as of this writing.
Futures provides some utility methods for chaining and composing Futures with Functions. Also provided are the makeChecked(), makeListenable(), makeUninterruptable() which can take a Future and make it checked, listenable, or uninterruptable, respectively. Could a FutureBuilder be in Guava's future?
This interface extends Future with an addListener() method that accepts both a Runnable listener and an Executor on which to execute the listener.
This class extends FutureTask and adds the ability to register listeners.
This is a ThreadFactory that can name threads by injecting the thread number into a given String pattern. This can reduce some boilerplate code
This is the implementation of TimeLimiter provided with Guava. Execution of proxy target methods happen in an ExecutorService that is provided during construction. If none is provided by caller, a Executors.newCachedThreadPool() is used.
This creates a proxy class that limits duration of all method calls on the target object.
This is an unchecked exception (extending RuntimeException makes it unchecked) that is thrown by SimpleTimeLimiter when a timeout occured.
An instance of this interface is returned by Futures.makeUninterruptable(). As expected, this Future continues to execute even if interrupted. If interrupted during execution, it will set the interrupted flag on the current Thread after it has completed executing.
This implementation of ListenableFuture can be used when result is already known, but something of type ListenableFuture is needed. This is public but used internally in the Futures class.


Guava is provided under the Apache open source license. This is considered a non-viral open-source license meaning that you are not required to release your source code even if it consumes Google Guava. Note that open source doesn't mean open commits. The Google project leadership provides strict editorial control over what changes may be made to the library. Guava runs on Java 5 virtual machines and newer.

Obtain Guava

As of this writing, there is no pre-built jar file of Google Guava provided. The best way to get started with Guava is to check it out of the Google Code repository. You will need a Subversion (svn) client for your platform. The following command will check out the latest version:

svn checkout http://guava-libraries.googlecode.com/svn/trunk/ guava

What's in the box?

When you check out Guava, you'll see a root and three top level directories: javadoc, lib, and src.

root directory
Ant build.xml file, Apache 2.0 license, and IntelliJ IDEA project metadata
the API documentation for Guava
any 3rd-party libraries used by Guava, currently only jsr305.jar, the annotations for software defect detection
the source code for Guava

The Ant build file.

To build Guava, set the JAVA5_HOME environment variable. Run something like the following command, substituting the location of your Java installation:

set JAVA5_HOME=C:\Program Files\Java\jdk1.6.0_18

Support for at least Java 5 is enforced in the build script. I used Sun's Java 6 update 18 JDK to compile with impunity.

There are only three targets: compile (default), javadoc, and clean.

The compile target will dump everything into build/classes.

The javadoc target will output to build/javadoc. You can override the Java property "version" (default value "snapshot") to affect the window titles in the javadocs.

Apparently Google internally uses its own JDK, as evidenced by the metadata present in the javadocs. Inside the original allclasses-frame.html you can see:

<!-- Generated by javadoc (build 1.6.0-google-internal) on Mon Jan 04 20:48:01 PST 2010 -->

but in my generated version you can see:

<!-- Generated by javadoc (build 1.6.0_18) on Sat Jan 16 11:11:38 CST 2010 -->


Guava can improve the productivity of any Java programmer who takes the time to learn the library. It does so in three ways.

First, it provides useful utilities to reduce the usage of error-prone code. For example, Charsets provides constants required to be part of every JDK. Otherwise, one would be forced to use String literals.

Second, it builds on existing JDK libraries to give added flexibility and power. For example PatternFilenameFilter, which brings together Regular expressions with java.io.FilenameFilter. Further examples are Splitter and Joiner. Splitter corrects many of the deficiencies found in the String.split() family of methods and takes advantage of the Builder pattern. JoinerSplitter's complement, eases the task of creating delimited Strings from String Arrays and Collections.

Finally, Guava is written by some very talented, yet pragmatic programmers and expresses the state-of-the-art of Java programming best practices and idioms.

For example, the builder pattern is used in the Splitter class. This has a practical effect of making a very common task, tokenizing Strings, easier, yet more flexible than ever before.

Another example is Throwables. Many times a developer simply doesn't know what to do with a checked exception and prints it to stdout, and happily moves on. Logged statements are easily missed or eaten by application frameworks. Throwables force the issue by at once making the code cleaner and easier to follow, and simultaneously throwing an unchecked exception to a higher level which will usually cause an application to "fail fast". The net result is an application developer that observes an application error dialog immediately upon encountering a defect, rather than strange behavior at a point later in the program.

For these reasons, Google Guava will reward the developer that learns it, even if she is unable to utilize it in production code at this time. Because Guava is in a very early stage, the API's may change. So, if you choose to incorporate Guava into your application now, please recognize that you will likely need to modify code to support later snapshots and releases of Guava.


Software Engineering Tech Trends (SETT) is a monthly newsletter featuring emerging trends in software engineering.

Check out OUR MOST POPULAR articles!