Google Guava

a library you should incorporate on any project


26 Nov 2016 View Comments
#java #computer #google #guava

Guava

Google Guava aka Google Collections Library

Last week, we talked about some convenient functions in Java. Here is a library which is a mother of all convenient functions. I met Google Guava about 2-3 years ago when I was working on MAWA Analyzer project and I have been staying a huge fan of it. Guava is a well-designed API which is meant to simplify your coding by introducing functions related to Collections, Functional Programming, Concurrency, Ordering, String Manipulations, IO Utilities, Reflection Utils, etc. Codes were advised and reviewed by Joshua Bloch, the author of Effective Java, which follows many of the patterns in the book such as the static factory, builder, immutability, null-checks, etc. Guava was open sourced as early as in 2007. The API uses Java Generics as Java 5 was already available at the time. Guava just makes the coding super exciting and fun!

Google Guava version 20.0 is out on October 28, 2016. See here to resolve dependency via Maven or Gradle. The listed items below are from Guava which I find convenient often times. They are mostly, if not all, supported in version 19.0 and up. In case you are still unsure on their usage, refer to their Java Doc. I strongly recommend at least have a look at their API doc. They just have so many functions I won’t be able to cover them all here. The functions introduced below are the ones I use and found themselves useful.

Item 1: Collection

This item is probably what made Guava famous. You can name a data structure to define using their static factory methods. There are ways to define structures:

:white_check_mark: Lists
Lists.newArrayList();
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);

Note: if the list is immutable, consider ImmutableList.reverse() instead.

List<Type> reversedList = Lists.reverse(theList);

Returns a view of the underlying list, partitioned into chunks of the specified size.

List<List<Integer>> parts = Lists.partition(countUp, 2);

remove all null values from a collection

List<String> values = Lists.newArrayList("a", null, "b", "c");
Iterable<String> withoutNulls = Iterables.filter(values, Predicates.notNull());

create immutable List directly

ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");

create immutable List from a standard collection

List<String> mutableList = Lists.newArrayList();
ImmutableList<String> immutableList = ImmutableList.copyOf(mutableList);

Using above copy using builder

List<String> mutableList = Lists.newArrayList();
ImmutableList<String> immutableList = 
    ImmutableList.<String> builder().addAll(mutableList).build();
:white_check_mark: Sets
Set<Type> aSet = Sets.newHashSet();

Sets support intersection as follows,

Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
// I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
return intersection.immutableCopy();

Sets also support cartesianProduct or powerSet function, {: style=”margin-bottom: .5em; margin-top: 1em;”}yy

Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");

Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// {"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
// {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}

Set<Set<String>> animalSets = Sets.powerSet(animals);
// {}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}

create immutable Set directly

ImmutableSet<String> immutableSet = ImmutableSet.of("a", "b", "c");

create immutable Set from a standard collection

Set<String> mutableSet = Sets.newHashSet();
ImmutableSet<String> immutableSet = ImmutableSet.copyOf(mutableSet);

Using above copy using builder

Set<String> mutableSet = Sets.newHashSet();
ImmutableSet<String> immutableSet = 
    ImmutableSet.<String> builder().addAll(mutableSet).build();
:white_check_mark: Maps
Maps.newLinkedHashMap();

difference:

Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);

diff.entriesInCommon(); // {"b" => 2}
diff.entriesDiffering(); // {"c" => (3, 4)}
diff.entriesOnlyOnLeft(); // {"a" => 1}
diff.entriesOnlyOnRight(); // {"d" => 5}

create immutable Map directly

ImmutableMap<String, String> imutableMap = 
    ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");

create immutable Map from a standard collection

Map<String, String> mutableMap = Maps.newHashMap();
ImmutableMap<String, String> imutableMap = ImmutableMap.copyOf(mutableMap);

Using above copy using builder

Map<String, String> mutableMap = Maps.newHashMap();
ImmutableMap<String, String> imutableMap = 
    ImmutableMap.<String, String> builder().putAll(mutableMap).build();

SortedMap:

    ImmutableSortedMap<String, Integer> salary = new ImmutableSortedMap
      .Builder<String, Integer>(Ordering.natural())
      .put("John", 1000)
      .put("Jane", 1500)
      .put("Adam", 2000)
      .put("Tom", 2000)
      .build();

Item 2: Ordering

Ordering is Guava’s “fluent” Comparator class, which can be used to build complex comparators and apply them to collections of objects. It’s basically a “comparator” instance. Examples are below:

assertTrue(byLengthOrdering.reverse().isOrdered(list));

natural()

Collections.sort(toSort, Ordering.natural());
assertTrue(Ordering.natural().isOrdered(toSort));

usingtoString()

List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());
 
Ordering<Integer> expectedOrder = Ordering.explicit(Lists.newArrayList(1, 11, 2));
assertTrue(expectedOrder.isOrdered(toSort));

Sort then Binary Search

List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());
int found = Ordering.usingToString().binarySearch(toSort, 2);

find min/max without sort

List<Integer> toSort = Arrays.asList(2, 1, 11, 100, 8, 14);
int found = Ordering.usingToString().min(toSort);
assertThat(found, equalTo(1));

Chaining 2 orderings

List<Integer> toSort = Arrays.asList(3, 5, 4, 1, 2);
Collections.sort(toSort, Ordering.natural().reverse());

nulls first

List<Integer> toSort = Arrays.asList(3, 5, 4, null, 1, 2);
Collections.sort(toSort, Ordering.natural().nullsFirst());
assertThat(toSort.get(0), nullValue());

Item 3: Strings

Until now, Strings are usually handled by company’s own implementation of “StringUtils”. This is typically a bad idea as there are libraries out there that handle most of the job. Trust these libraries for 2 main reasons. First, hundreds of people have laid their eyes on the codes online (open-sourced libraries). Second, a lot of people are using them. There are other options for StringUtils than Guava. There is Apache Commons. The project started n 2002. Somewhat Old. Still, has quite useful libraries. I love their StringBuilder/StringWriter functions. Guava has their lovely ones too such as Joiner, Splitter and especially CharMatcher. See below:

Joiner:

Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("Harry", null, "Ron", "Hermione");

Or you can just straight apply,

Joiner.on(",").join(Arrays.asList(1, 5, 7)); // returns "1,5,7"

Splitter:

Splitter.on(',')
       .trimResults()
       .omitEmptyStrings()
       .split("foo,bar,,   qux");

CharMatcher, this is my favourite, I felt like writing a poem when I first used it:

private CharMatcher FILTER = CharMatcher.anyOf("-.;").precomputed();

You can run one of the following functions,

String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(string); // remove control characters
String theDigits = CharMatcher.DIGIT.retainFrom(string); // only the digits
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' ');
  // trim whitespace at ends, and replace/collapse whitespace into single spaces
String noDigits = CharMatcher.JAVA_DIGIT.replaceFrom(string, "x"); // mark x all digits
String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(string);
  // eliminate all characters that aren't digits or lowercase

Charsets:

bytes = string.getBytes(Charsets.UTF_8);

Item 4: Comparison Chain

Your traditional compareTo method might look like this:

1
2
3
4
5
6
7
8
9
10
11
    @Override
    public int compareTo(User that) {
        int result = 0;

        result = userId != null ? userId.compareTo(that.getUserId()) : result;
        result = result == 0 ? personName.compareTo(that.getPersonName()) : result;
        result = result == 0 ? age.compareTo(that.getAge()) : result;
        result = result == 0 ? address.compareTo(that.getAddress()) : result;

        return result;
    }

Now, above can be shortened using Guava like this.

1
2
3
4
5
6
7
8
public int compareTo(User that) {
   return ComparisonChain.start()
       .compare(userId, that.getUserId())
       .compare(personName, that.getPersonName(), Ordering.natural().nullsFirst())
       .compare(age, that.getAge(), Ordering.natural().nullsFirst())
       .compare(address, that.getAddress())
       .result();
}

Look how clean it is. It’s also just beautiful that you can apply Ordering in this chain. Ordering is basically used as a comparator.

Conclusion

Don’t use your own Utils functions. Use only ones applicable specific to your project. There are many other options for Utils. However, at least for Java, Big 2 Java Collections Library is, Apache Commons and Google Guava. These libraries use names very well made usage so much easier and fun. There will be a time where you can solve your issues using one of these libraries, trust me :smile: Make sure you check them first and see if you can incorporate these libraries into your project. Also, please check out my github for test cases on Guava library. I have mostly covered examples I discussed in this blog. I may have added one or two more than what has covered here actually hehe :+1:

Share this post

Me

I am a passionate software developer working in Downtown, Vancouver. I strongly believe in art of algorithms and together with it to write clean and efficient software to build awesome products. If you would like to connect with me, choose one from below options :) You can also send me an email at