Google Guava Libraries Essentials

I want code to be simple-n-short, on-point and easy to read. Unnecessary complexity distract and obscure understanding of what is really going on and can be a real killer for productivity.

You know, tangled for-loops and indexes to track, if/else and switch cases, null/validation checks, converting/copying/deleting/sorting collections, exception handling … the list goes on along with ever-increasing line numbers and maintenance burden.

An excellent quote by Tony Hoare comes to mind.

There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies.

In other words: The Devil is in the details.

Apache Commons have some of most wonderful libraries complementing the JDK APIs, but this post is not about Commons. It is about Google Guava which is similar to Commons in many regards. It provide a single library for commonly used day-to-day tasks, such as collection handling, string manipulation, concurrency, IO, primitives, exceptions etc.

There is so much nice stuff in Guava and I wont have time to go through the complete library, but here at least some examples of what it can do.

Objects
Objects makes it easy to implement hashcode/equals without cluttering your classes too much (Eclipse auto-generation tends to be a bit verbose for my taste).

Classes that implement toString are really pleasant to use when doing debugging and logging, but can be a real pain implement. Objects.toStringHelper makes this really easy and also help maintaining a consistent format for printing objects.

public class Item {
  private String id;
  private String name;
 
  public Item(String id, String name) {
    this.id = id;
    this.id = name;
  }
 
  public String getId() {
    return id;
  }
 
  public String getName() {
    return name;
  }
 
  @Override
  public int hashCode() {
    return Objects.hashCode(getId(), getName());
  }
 
  @Override
  public String toString() {
    return Objects.toStringHelper(this).add("id", getId()).add("name", getName()).toString();
  }
 
  @Override
  public boolean equals(Object o) {
    if (!(o instanceof Item)) {
      return false;
    }
    Item other = (Item) o;
    return Objects.equal(getId(), other.getId()) && Objects.equal(getName(), other.getName());
  }
}

Printing this class outputs something like this.

Item{id=1, name=Book}

Throwables
Wrapping the original exception object is not always appropriate, because it can cause ClassNotFoundException in the client code if communication occur between unrelated class loaders or if they are serialized on the wire. Throwables can decouple this dependency, still allowing remote clients to see the stack trace by converting it to a string.

try {
  // throws implementation specific exception
} catch (InternalException e) {
  throw new ApiException("reason", Throwables.getStackTraceAsString(e));
}

Iterables
Concatenating two separate collections and performing operations on the result can cause a quite a lot of clutter. Iterables to the rescue. Take a minute and think how code might look without Iterables.concat.

for (Item item : Iterables.concat(books, electronics)) {
  // do something useful
}

Multimaps
Multimap is like a Map, but allow multiple values to be stored for every key. The following example is a a variant of a typesafe hetereogeneous container using multimap to realize a product catalogue of items.

public class ProductCatalogue {
  private Multimap<Class,? extends Item>, Item> catalogue = ArrayListMultimap.create();
 
  public void add(Item item) {
    catalogue.put(item.getClass(), item);
  }
 
  public <T extends Item> Collection<Item> list(Class<T> clazz) {
    return catalogue.get(clazz);
  }
}
 
ProductCatalogue catalogue = new ProductCatalogue();
catalogue.add(new Book("1", "Book1"));
catalogue.add(new Movie("2", "Movie1"));
// only get books
System.out.println("Books " + catalogue.list(Book.class));
// only get movies
System.out.println("Movies " + catalogue.list(Movie.class));

BiMap
BiMap implement a one-to-one bidirectional relationship between key and value of the Map. Here is an example using language code to get the language and vice versa.

BiMap<String, String> languageCodes = HashBiMap.create();
languageCodes.put("en", "English");
languageCodes.put("fr", "French");
languageCodes.put("zh", "Chinese");
assert "English" == languageCodes.get("en");
assert "en" == languageCodes.inverse().get("English");

Preconditions
Most classes have restrictions on values given them in constructor and methods. Invalid values should be escalated as soon as possible by doing explicit validity checks before execution. It is a lot better to fail-fast than to fail later with an unexpected exception or worse, silently compute the wrong result.

public Item(String id, String name) {
  this.id = Preconditions.checkNotNull(id, "id must not be null");
  this.name = Preconditions.checkNotNull(name, "name must not be null");
  Preconditions.checkArgument(name.length() > 6, "name must be longer than 6 chars");
}

Constraints
Constraints are similar to preconditions in a way that they can restrict what values are added to a collection. This makes collections much easier to use and code a lot cleaner, since constraints are separated from business code.

public class Voyage {
  private Country targetcountry;
  private int capacity;
  private List<Cargo> items = Constraints.constrainedList(new ArrayList<Cargo>(), new Constraint<Cargo>() {
    @Override
    public Cargo checkElement(Cargo cargo) {
      Preconditions.checkNotNull(cargo);
      Preconditions.checkArgument(targetcountry.allows(cargo));
      Preconditions.checkArgument(cargo.getUnits() gt; 0);
      return cargo;
    }
  });
 
  public void load(List<Cargo> cargos) {
    items.addAll(cargos);
  }
}

Predicates and Functions
Predicates evaluate if something is true or false but can also be combined into more complex evaluations using “and”, “or”, “not” and “in”.

What normally would require a for-loop and bunch of if statements can now be reduced to a one-liner. How sweet is that?

Predicate<Item> heavyItemPolicy = new Predicate<Item>() {
  @Override
  public boolean apply(Item item) {
    if(item.getWeight() > 1000){
      return true;
    }
    return false;
  }
};
Collection<Item> heavyItems = Collections2.filter(order, heavyItemPolicy);

You can also use Maps.filterKeys or Iterables.filter in a similar way. But keep in mind that removal from modification is bidirectional. e.g. removal from the origin affect result and vice versa.

Functions on the other hand, is a way of transforming one object to another. For example, convert concurrency on a order of items.

Function currencyConverter = new Function<Double, Item>() {
  @Override
  public Double apply(Item item) {
   return item.getPrice() * ANOTHER_CURRENCY;
  }
}
Collection<Double> prices = Collections2.transform(order, currencyConverter);

You can also use Maps.transformValues or Iterables.transform in a similar way.

A Query API
I have been think about how to create simple but powerful Fake Objects for some time now. But I dont want fakes themselves to turn into a maintenance burden, so they must be easy to implement. My intuition tells me i need a general purpose state management framework for this to work. And so using predicates, I created a small fluent query interface interacting with an in memory storage.

InMemoryStorage storage = new InMemoryStorage();
// add a few Item.class objects to storage
Criteria middleprice = field("price").is(largerThan(100)).and(lessThan(200));
Criteria expired = field("expires").is(after(currentDate));
Collection<Item> result = storage.select(middleprice.and(not(expired))).from(Item.class);

I feel quite satisfied with the result actually – short, compact, understandable and typesafe.

Im not going to go into the details here, but please do inspect the implementation of Criteria and InMemoryStorage, as well as the tests.

I hope these examples will trigger you to explore Guava further and use it to make your code more readable, robust and maintainable.

And lastly, I really do hope many of these facilities reach standard Java some day soon.

Reference: The Devil is in the details from our JCG partner Kristoffer Sjögren at the Deep Hacks blog.

Related Articles :

Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

One Response to "Google Guava Libraries Essentials"

  1. rami outa says:

    Hello,
    I need to create a java library for my project. I am creating a small language and I want to write this language in the java code normally so I have to import a library that I will create in order to do so. Can anyone help me in creating the library?

    Thanks
    my email is rami.outa@gmail.com

Leave a Reply


+ seven = 12



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.