Introduction to Google Guava

This tutorial is an introduction to the Guava library. We look at some interesting features of the Guava library.

Guava

Google Guava is an open-source set of common libraries for Java, mainly developed by Google engineers. Google has many Java projects. Guava is a solution for many common problems encountered in those projects, including areas of collections, math, functional idioms, input & output, and strings.

Some of the Guava's features were already included in the JDK; for instance the String.join() method was introduced into JDK 8.

Guava Maven dependency

In our examples, we use the following Maven dependency.

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>19.0</version>
</dependency>

Guava initializing collections

Guava allows to initialize collections in one line. JDK 8 does not have support for collection literals.

InitializeCollectionEx.java
package com.zetcode.initializecollectionex;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;

public class InitializeCollectionEx {

    public static void main(String[] args) {

        Map items = ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1);

        items.entrySet()
                .stream()
                .forEach(System.out::println);
        
        List<String> fruits = Lists.newArrayList("orange", "banana", "kiwi", 
                "mandarin", "date", "quince");
        
        for (String fruit: fruits) {
            System.out.println(fruit);
        }
    }
}

In the example, we create a map and a list using Guava's factory methods.

Map items = ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1);

A new map is created with the ImmutableMap.of() method.

List<String> fruits = Lists.newArrayList("orange", "banana", "kiwi", 
        "mandarin", "date", "quince");

A new list of strings is created with the Lists.newArrayList() method.

coin=3
glass=4
pencil=1
orange
banana
kiwi
mandarin
date
quince

This is the output of the example.

Guava MoreObjects.toStringHelper()

The MoreObjects.toStringHelper() helps to create toString() methods with a consistent format easily, and it gives us control over what fields we include.

Car.java
package com.zetcode.tostringex.beans;

import com.google.common.base.MoreObjects;

public class Car {

    private long Id;
    private String Name;
    private int Price;

    public Car(long Id, String Name, int Price) {
        this.Id = Id;
        this.Name = Name;
        this.Price = Price;
    }
    
    public long getId() {
        return Id;
    }

    public void setId(long Id) {
        this.Id = Id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String Name) {
        this.Name = Name;
    }

    public int getPrice() {
        return Price;
    }

    public void setPrice(int Price) {
        this.Price = Price;
    }
    
   @Override
    public String toString() {
        return MoreObjects.toStringHelper(Car.class)
            .add("id", Id)
            .add("name", Name)
            .add("price", Price)
            .toString();
    }    
}

This is a Car bean. It contains a toString() method which gives a string representation of the object.

@Override
public String toString() {
    return MoreObjects.toStringHelper(Car.class)
        .add("id", Id)
        .add("name", Name)
        .add("price", Price)
        .toString();
}  

Instead of concatenating strings we have a cleaner solution with the MoreObjects.toStringHelper() method.

ToStringEx.java
package com.zetcode.tostringex;

import com.zetcode.tostringex.beans.Car;

public class ToStringEx {
    
    public static void main(String[] args) {
        
        Car car1 = new Car(1, "Audi", 52642);
        Car car2 = new Car(2, "Mercedes", 57127);
        Car car3 = new Car(3, "Skoda", 9000);

        System.out.println(car1);
        System.out.println(car2);
        System.out.println(car3);
    }
}

We create three car objects and pass them to the System.out.println() method. The method invokes the objects' toString() methods.

Car{id=1, name=Audi, price=52642}
Car{id=2, name=Mercedes, price=57127}
Car{id=3, name=Skoda, price=9000}

This is the output of the example.

Guava FluentIterable

FluentIterable provides a powerful yet simple API for manipulating Iterable instances in a fluent manner. It allows us to filter and transform collections in various ways.

Car.java
package com.zetcode.fluentiterable.beans;

import com.google.common.base.MoreObjects;

public class Car {

    private long Id;
    private String Name;
    private int Price;

    public Car(long Id, String Name, int Price) {
        this.Id = Id;
        this.Name = Name;
        this.Price = Price;
    }
    
    public long getId() {
        return Id;
    }

    public void setId(long Id) {
        this.Id = Id;
    }

    public String getName() {
        return Name;
    }

    public void setName(String Name) {
        this.Name = Name;
    }

    public int getPrice() {
        return Price;
    }

    public void setPrice(int Price) {
        this.Price = Price;
    }
    
   @Override
    public String toString() {
        return MoreObjects.toStringHelper(Car.class)
            .add("id", Id)
            .add("name", Name)
            .add("price", Price)
            .toString();
    }    
}

In this example, we have a Car bean.

FluentIterableEx.java
package com.zetcode.fluentiterable;

import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.zetcode.fluentiterable.beans.Car;
import java.util.List;

public class FluentIterableEx {

    public static void main(String[] args) {

        List<Car> cars = Lists.newArrayList(new Car(1, "Audi", 52642),
                new Car(2, "Mercedes", 57127), new Car(3, "Skoda", 9000),
                new Car(4, "Volvo", 29000));

        Predicate<Car> byPrice = car -> car.getPrice() <= 30000;

        List<String> results = FluentIterable.from(cars)
                .filter(byPrice)
                .transform(Functions.toStringFunction())
                .toList();
        
        System.out.println(results);
    }
}

In the code example, we have a list of car objects. We transform the list by reducing it only to cars which are less expensive than 30000 units.

List<Car> cars = Lists.newArrayList(new Car(1, "Audi", 52642),
        new Car(2, "Mercedes", 57127), new Car(3, "Skoda", 9000),
        new Car(4, "Volvo", 29000));

A list of Car objects is created. There are no collection literals in JDK. We use Lists.newArrayList() from Guava to initialize the list.

Predicate<Car> byPrice = car -> car.getPrice() <= 30000;

A Predicate is created. A predicate is a function that returns a boolean value. This predicate determines whether the car is less expensive than 30000.

List<String> results = FluentIterable.from(cars)
        .filter(byPrice)
        .transform(Functions.toStringFunction())
        .toList();

A FluentIterable is created from the cars collection. The predicate function is applied on the FluentIterable. The retrieved elements are transformed into a list of elements; the elements are strings returned from the toString() function.

[Car{id=3, name=Skoda, price=9000}, Car{id=4, name=Volvo, price=29000}]

This is the output of the example.

Guava predicate

In general meaning, a predicate is a statement about something that is either true or false.

The Predicates.notNull() returns a predicate that evaluates to true if the object reference being tested is not null.

PredicateEx.java
package com.zetcode.predicateex;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.List;

public class PredicateEx {

    public static void main(String[] args) {

        List<Integer> values = Lists.newArrayList(3, null, 4, 7, 
                8, null, 7);
        
        Iterable<Integer> filtered = Iterables.filter(values, 
                Predicates.notNull());
        
        for (Integer i: filtered) {
            System.out.println(i);
        }
    }
}

In the first example, we use a predicate to exclude null values from a collection.

List<Integer> values = Lists.newArrayList(3, null, 4, 7, 
        8, null, 7);

Using Guava's Lists.newArrayList(), we create a list of Integer values. The list contains two nulls.

Iterable<Integer> filtered = Iterables.filter(values, 
        Predicates.notNull());

We filter the values by applying the Predicates.notNull(). The Iterables.filter returns an iterable object.

for (Integer i: filtered) {
    System.out.println(i);
}

We go through the filtered list and print its elements.

3
4
7
8
7

This is the output of the example.

The second example filters a collection by a specific textual pattern. In programming, predicates are often used to filter data.

PredicateEx2.java
package com.zetcode.predicateex;

import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;

public class PredicateEx2 {

    public static void main(String[] args) {

        List<String> items = Lists.newArrayList("coin", "book",
                "cup", "purse", "bottle");
        Collection<String> result  = Collections2.filter(items, 
                Predicates.containsPattern("o"));
        
        for (String item: result) {
            System.out.println(item);
        }
    }
}

The code example creates a list of items and later filters the list by a specific pattern.

Collection<String> result = Collections2.filter(items, 
        Predicates.containsPattern("o"));

The Predicates.containsPattern() returns a predicate that looks for items containing character 'o'. The predicate is passed to the Collections2.filter() method.

coin
book
bottle

These three words meet the criteria.

Reading all lines with Guava

The Files.readLines() allows to read all lines from a file in one shot.

NetBeans project structure
Figure: NetBeans project structure

The figure shows how the project structure looks in NetBeans.

balzac.txt
Honoré de Balzac, original name Honoré Balzac (born May 20, 1799, Tours, 
France—died August 18, 1850, Paris) French literary artist who produced 
a vast number of novels and short stories collectively called 
La Comédie humaine (The Human Comedy). He helped to establish the traditional 
form of the novel and is generally considered to be one of the greatest 
novelists of all time.

We have this textual file in the src/main/resources directory.

ReadingLinesEx.java
package com.zetcode.readinglinesex;

import com.google.common.base.Charsets;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class ReadingLinesEx {

    public static void main(String[] args) throws IOException {
        
        String fileName = "src/main/resources/balzac.txt";
        
        List<String> lines = Files.readLines(new File(fileName), 
                Charsets.UTF_8);
        
        for (String line: lines) {
            System.out.println(line);
        }
    }
}

The example reads all lines from the balzac.txt file and prints them to the console.

String fileName = "src/main/resources/balzac.txt";

The file name is located in the src/main/resource directory.

List<String> lines = Files.readLines(new File(fileName), 
        Charsets.UTF_8);

With the Files.readLines() method, we read all lines from the balzac.txt file. The lines are stored in the list of strings.

for (String line: lines) {
    System.out.println(line);
}

We go through the list and print its elements.

Creating a new file with Guava

The Files.touch() method is used to create a new file or to update the timestamp on an existing file. The method is similar to the Unix touch command.

TouchFileEx.java
package com.zetcode.touchfileex;

import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;

public class TouchFileEx {

    public static void main(String[] args) throws IOException {
        
        String newFileName = "newfile.txt";
        
        Files.touch(new File(newFileName));
    }
}

The example creates a newfile.txt in the project's root directory.

Writing to a file with Guava

The Files.write() method writes data to a file.

WriteToFileEx.java
package com.zetcode.writetofileex;

import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;

public class WriteToFileEx {

    public static void main(String[] args) throws IOException {
        
        String fileName = "fruits.txt";
        File file = new File(fileName);
        
        String content = "banana, orange, lemon, apple, plum";
        
        Files.write(content.getBytes(), file);
    }
}

The example writes a string consisting of fruit names to the fruits.txt file. The file is created in the project root directory.

Joining strings with Guava

The Joiner joins pieces of text (specified as an array, Iterable, varargs, or a Map) with a separator.

StringJoinerEx.java
package com.zetcode.stringjoinerex;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import java.util.List;

public class StringJoinerEx {
    
    public static void main(String[] args) {
        
        List<String> myList = Lists.newArrayList("8", "2", "7", "10");
        
        String result = Joiner.on(",").join(myList);
        
        System.out.println(result);
    }
}

In the example, we join elements of a list with a comma character.

8,2,7,10

This is the output of the example.

Splitting strings with Guava

The Splitter extracts non-overlapping substrings from an input string by recognizing appearances of a separator sequence.

StringSplitterEx.java
package com.zetcode.stringsplitterex;

import com.google.common.base.Splitter;
import java.util.List;

public class StringSplitterEx {
    
    public static void main(String[] args) {
        
        String input = "There is a dog in the garden.";
        
        List<String> words = Splitter.on(" ").splitToList(input);
        
        for (String word: words) {
            System.out.println(word);
        }
    }
}

The example uses the Splitter to split a sentence into words.

String input = "There is a dog in the garden.";

We have a sentence consisting of seven words.

List<String> words = Splitter.on(" ").splitToList(input);

The separator is a single space character. The splitToList() method splits the input into a list of strings.

The second example splits the input into three substrings.

StringSplitterEx2.java
package com.zetcode.stringsplitterex2;

import com.google.common.base.Splitter;
import java.util.List;

public class StringSplitterEx2 {
    
    public static void main(String[] args) {
        
        String input = "coin, pencil, chair, bottle, soap";
        
        List<String> words = Splitter.on(",")
                .trimResults()
                .limit(3)
                .splitToList(input);
        
        for (String word: words) {
            System.out.println(word);
        }
    }
}

In addition, the words are trimmed.

coin
pencil
chair, bottle, soap

This is the output.

Guava preconditions

Preconditions are simple static methods to be called at the start of our own methods to verify correct arguments and state. The methods throw IllegalArgumentException on failure.

PreconditionsEx.java
package com.zetcode.preconditionex;

import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.base.Splitter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class PreconditionsEx {

    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Enter items: ");
        String input = br.readLine();

        List<String> items = Splitter.on(" ").splitToList(input);
        OutputItems(items);
    }

    public static void OutputItems(List<String> items) {
        checkArgument(items != null, "The list must not be null");
        checkArgument(!items.isEmpty(), "The list must not be empty");

        for (String item: items) {
            System.out.println(item);
        }
    }
}

The example uses two preconditions.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter items: ");
String input = br.readLine();

We read input from the user. We expect a list of words.

List<String> items = Splitter.on(" ").splitToList(input);
OutputItems(items);

The words specified are split into a list and the list is passed to the OutputItems() method

checkArgument(items != null, "The list must not be null");
checkArgument(!items.isEmpty(), "The list must not be empty");

In the OutputItems() method we check that the list is not null and empty. With the checkArgument() method we ensure the validity of an expression; e.g. that the list is not null.

Calculating factorial with Guava

Guava has also tools for doing math calculations. The BigIntegerMath.factorial() computes a factorial.

FactorialEx.java
package com.zetcode.factorialex;

import com.google.common.math.BigIntegerMath;

public class FactorialEx {

    public static void main(String[] args) {

        System.out.println(BigIntegerMath.factorial(100));
    }
}

The example prints the factorial of number 100.

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

This is the output of the example.

Calculating binomial with Guava

The BigIntegerMath.binomial() returns the binomial coefficient of n and k.

FactorialEx.java
package com.zetcode.binomialex;

import com.google.common.math.BigIntegerMath;
import java.math.BigInteger;

public class BinomialEx {
    
    public static void main(String[] args) {
        
        BigInteger bigInt = BigIntegerMath.binomial(4, 2);
        System.out.println(bigInt);
    }
}

The example prints the binomial of 4 and 2.

Guava CharMatcher

CharMatcher provides some basic text processing methods.

CharMatcherEx.java
package com.zetcode.charmatcherex;

import com.google.common.base.CharMatcher;

public class CharMatcherEx {

    public static void main(String[] args) {

        String input = "Peter17";

        CharMatcher matcher = CharMatcher.JAVA_LETTER;
        String result = matcher.retainFrom(input);
        
        System.out.println(result);
    }
}

The example removes any non-letter characters from the input string. The retainFrom() method returns a string containing all matching characters of a character sequence, in order.

Peter

The two digits are removed.

In the second example, we count the number of characters in the input strings.

CharMatcherEx2.java
package com.zetcode.charmatcherex2;

import com.google.common.base.CharMatcher;

public class CharMatcherEx2 {

    public static void main(String[] args) {

        String input = "Beautiful sunny day";
        
        int n1  = CharMatcher.is('n').countIn(input);
        System.out.format("Number of n characters: %d%n", n1);

        int n2  = CharMatcher.is('i').countIn(input);
        System.out.format("Number of i characters: %d", n2);
    }
}

The example counts the number of 'n' and 'i' characters in the input string.

int n1  = CharMatcher.is('n').countIn(input);

The countIn() method returns the number of matching characters found in the character sequence.

Number of n characters: 2
Number of i characters: 1

This is the output of the example.

The CharMatcher.whitespace() determines whether the character is a white space.

CharMatcherEx3.java
package com.zetcode.charmatcherex3;

import com.google.common.base.CharMatcher;

public class CharMatcherEx3 {

    public static void main(String[] args) {

        String input = "   yogurt \t";

        String result = CharMatcher.whitespace().trimFrom(input);

        System.out.println(input + " and bread" );
        System.out.println(result + " and bread");
    }
}

In the third example, we remove white space from the string.

String result = CharMatcher.whitespace().trimFrom(input);

The white space is removed from the input string.

   yogurt        and bread
yogurt and bread

This is the output of the example.

Guava Ranges

Range allows to create various ranges easily. A range, or interval, defines the boundaries around a contiguous span of values; for example, integers from 1 to 10 inclusive.

RangeEx.java
package com.zetcode.rangeex;

import com.google.common.collect.Range;

public class RangeEx {

    public static void main(String[] args) {
        
        Range<Integer> range1 = Range.closed(3, 8);
        System.out.println(range1);
        
        Range<Integer> range2 = Range.openClosed(3, 8);
        System.out.println(range2);

        Range<Integer> range3 = Range.closedOpen(3, 8);
        System.out.println(range3);
    }
}

In the example, we create three integer intervals.

[3‥8]
(3‥8]
[3‥8)

This is the output of the example.

In this article, we have worked with the Google Guava library.

You might also be interested in the following related tutorials: Reading text files in Java, Java tutorial, Filtering a list in Java, Joining strings with Java 8's StringJoiner, or Opencsv tutorial.