January 25, 2020

Google Guava: 5 Things You Never Knew It Could Do

Table of Contents

What are some of the lesser-known features of Google Guava that every developer could use?

It’s one of the most popular libraries out there, it’s open source, you probably know it already, and it comes from a place where people play Quidditch as a real sport (at least on The Internship). It’s not the Hogwarts library from Harry Potter but it does have lots of spells up its sleeve: Google Guava contains a range of core Java libraries that were born internally at Google, battle-tested in production and publicly released. And it also had Optional before it appeared on Java 8.


The main focus of Guava is improving the workflow around common tasks with utilities that help write better, cleaner code, and be more productive. Most famous for its collections and caching capabilities, it contains many more useful yet little known features. For collections and caching it introduced improvements on the JDKs collection API and filled in the void of the missing JCache that was finally released last year. In this post, I’d like to share with you some of Google Guava’s features we like  and some more interesting discoveries that we just made.

Note: Guava supports Java 6 and above.

1. Unsigned Primitives: They exist!

One of the lesser-known features of Java 8 is a new workaround for Unsigned Primitives in the Integer class. An even lesser-known feature of Guava is that all of this has already been available years before the Java 8 release and can be used today for Java 6 and above. Let’s get a peek of how it’s handled in Guava. We have 2 options before us and it’s up to us to remain consistent:


Dealing with the primitive type directly as int, and keeping in mind it’s Unsigned in our logic:


[java]
int notReallyInt = UnsignedInts.parseUnsignedInt(4294967295); // Max unsigned int
String maxUnsigned = UnsignedInts.toString(notReallyInt); // We’re legit!
[/java]


UnsignedInts and UnsignedLongs also support methods like compare, divide, min, max and more.
A wrapper to avoid dealing with primitives directly and cause mistakes:


[java]
UnsignedInteger newType = UnsignedInteger.valueOf(maxUnsigned);
newType = newType.plus(UnsignedInteger.valueOf(“1”)); // Increment
[/java]


UnsignedInteger and UnsignedLong also support methods like minus, times, dividedBy and mod. Read more on Guava’s wiki

2. Hashing: 128bit MurmurHash for the win

When looking into the non-cryptographic hashing capabilities we get with the standard Java library, one thing we really miss is the MurmurHash. It’s simple, fast, distributed evenly and has great support in many languages. Not to replace Java’s hashCode() but great if you need to generate many hashes, when 32bit isn’t enough, and you need it done super fast without hurting your performance. Here’s how it goes on Guava:


[java]
HashFunction hf = Hashing.murmur3_128(); // 32bit version available as well
HashCode hc = hf.newHasher()
.putLong(id)
.putString(name, Charsets.UTF_8)
.putObject(person, personFunnel)
.hash();
[/java]

Decomposing objects is done using a Funnel that includes instructions on how to read the object, so if we have a Person with an id, name and birth year:


[java]
Funnel<Person> personFunnel = new Funnel<Person>() {
@Override
public void funnel(Person person, PrimitiveSink into) {
into
.putInt(person.id)
.putString(person.firstName, Charsets.UTF_8)
.putString(person.lastName, Charsets.UTF_8)
.putInt(birthYear);
}
};
[/java]


Read more on Guava’s wiki

3. InternetDomainName: Will replace your domain name validator

Another cool little utility with Guava is an InternetDomainName, which unsurprisingly helps parse and manipulate domain names. If you’ve ever written a similar utility yourself, you’ll appreciate how this helps solve it quickly and in an elegant way. And valid according to updating RFC specifications, using the list of domains from the Public Suffix List, an initiative by the Mozilla foundation. Overall it also has more specific methods than the apache-commons validator equivalent. Let’s see a quick example:


[java]
InternetDomainName owner =
InternetDomainName.from(“blog.overops.com”).topPrivateDomain(); // returns takipi.com
InternetDomainName.isValid(“takipi.monsters”); // returns false
[/java]


A few concepts that can be confusing around domain names:


publicSuffix() – The top domain that is a separate entity according to the the Public Suffix List. So we’ll have results like co.uk, .com, .cool (yes, it’s a real suffix and javais.cool & scalais.cool).


topPrivateDomain() – The top domain that is a separate entity according to the the Public Suffix List (PSL). Applying it on blog.overops.com returns takipi.com, BUT if you try it on a Github pages site, username.github.io will retrurn username.github.io since it’s a separate entity that appears on the PSL.


This utility comes in handy when you need to validate domains, like in the JIRA integration we recently added to Takipi where first we check your JIRA host before connecting it to Takipi’s production error analysis tool.


Read more on Guava’s wiki

4. ClassPath Reflection: Mirror mirror on the wall

When inspecting Java’s Reflection capabilities, the ability to inspect our own code, you’ll find that there’s no simple way to get a list of all the classes in your package or project. This is one of the Guava features we really like, as it helps get more information about the environment you’re running on. It works as simple as that:


[java]
ClassPath classpath = ClassPath.from(classloader);
for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses(“com.mycomp.mypackage”)) {
System.out.println(classInfo.getName());
}
[/java]


This snippet will loop through and print out all the class names in the package we specified. One thing worth mentioning here is that the scan includes only the classes that are physically under the package we mention. It will not include classes loaded from other places, so be careful with what you use it for as it will sometimes give you an incomplete picture.


Read more on Guava’s wiki

5. CharMatcher: Simplified Regex?

Let’s end this feature roundup with another problem I’m sure you’ll recognize. You have a string or a series of strings that you want to format in a certain, remove whitespaces or other characters, replace a specific character, stip the digits or what not. Generally, grab characters that match some pattern and do something with it. Here Guava provided the CharMatcher method for elegant handling of such problems.


For this task, we have some predefined patterns like JAVA_UPPER_CASE (uppercase characters), JAVA_DIGIT (digits), INVISIBLE (Invisible unicode characters) and many more. Beyond the predefined patterns, we can have a go at this ourselves and create patteres of our own. Let’s see how this works with a quick code sample:


String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ‘ ‘);


This will trim all whitespaces from the end of the string and merge all subsequent whitespaces into one.


[java]
String keepAlex = CharMatcher.anyOf(“alex”).retainFrom(someOtherString);
[/java]


This line will take a String and strip it of all the characters that don’t appear in my name. If I’ll ever be a rapper, that’s how all my songs would start 🙂
Read more on Guava’s wiki

Conclusion

We’ve seen some of the most interesting features of Google Guava, excluding the popular collections and cache libraries. Some of these are used heavily in OverOps, and others are useful things that we think many projects could benefit from. Google Guava helps developers be productive, and that’s exactly what we at OverOps aim to achieve with the tools we’re developing (which are super cool btw, but hey, I’m probably biased).
We’re curious to know, which other Guava features you use that most developers don’t? (Collections and caching doesn’t count!).

Service Reliability Management