Guava ImmutableList Examples

0

An ImmutableList is a List whose contents are immutable so can’t be modified. One may wonder how different it is from Collections.unmodifiableCollection?

Once a list is created, you can’t add, remove or modify elements whereas the contents returned by Collections.unmodifiableCollection change whenever the wrapped collection is modified.

Sub-classing may allow a back door entry to modify the list as one can override the immutable methods and change their behavior, which is why, overriding the mutating methods is prohibited in ImmutableList. For example, the below add() method from ImmutableList throws UnsupportedOperationException and is a final method.

  public final void add(int index, E element) {
    throw new UnsupportedOperationException();
  }

ImmutableList offers complete guarantee of immutability thus is safe to access this collection concurrently from multiple threads.

You may also want to read my latest article on Guava Predicate Examples.

Dependency

Add guava artifactId, version 18.0 to your pom.xml.

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javarticles.guava</groupId>
	<artifactId>guavaEventBusExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>18.0</version>
		</dependency>
	</dependencies>
</project>

Different ways to create ImmutableList

  1. Using of – call this if have an explicit list of elements or entries.
  2. Using copyOf – call this if you already have an existing collection and you need an immutable list with the same contents.
  3. Using Builder – this follows the builder pattern, you can use this if you want to build the list from multiples sources.

We will look into each style of creation but first let’s see how one can change the contents of a list returned by Collections.unmodifiableCollection.

Collections.unmodifiableCollection Example

In the below example of Collections.unmodifiableCollection, we modify the contents by modifying the wrapped list.

UnmodifiableCollectionExample:

package com.javarticles.collections;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class UnmodifiableCollectionExample {
    public static void main(String[] args) {
        List list = Arrays.asList("Once", "upon",
                "time", "there", "used", "to", "be", "king");
        System.out.println("List to be modified: " + list);
        Collection unmodifiableList = Collections.unmodifiableCollection(list);
        System.out.println("Modify the wrapped list");
        list.set(7, "AN EMPEROR");
        System.out.println("After the change:" + unmodifiableList);
    }
}

Output:

List to be modified: [Once, upon, time, there, used, to, be, king]
Modify the wrapped list
After the change:[Once, upon, time, there, used, to, be, AN EMPEROR]

Now let’s get started with some examples of ImmutableList.

ImmutableList creation using of()

We have many overloaded methods of ImmutableList.of based on the number of elements you pass in. The list created will have the elements in the same order as the order of arguments. Thus the iteration order is always the way the list was created. You can pass in as many elements as you want to of method. Once the argument count goes up to eleven, the of method with the varargs form will come into picture.

ImmutableListOfExample:

package com.javarticles.guava;

import java.util.List;
import java.util.function.Consumer;

import com.google.common.collect.ImmutableList;

public class ImmutableListOfExample {
    public static void main(String[] args) {
        List<String> emptyList = ImmutableList.of();
        verifyElements("ImmutableList.of()", emptyList);

        List<String> singletonList = ImmutableList.of("I am Single");
        verifyElements("ImmutableList.of(\"I am Single\")", singletonList);

        List<String> dualElementList = ImmutableList.of("Me", "and you");
        verifyElements("ImmutableList.of(\"Me\", \"and you\")", dualElementList);

        List<String> multipleElements = ImmutableList.of("Once", "upon",
                "time", "there", "used", "to", "be", "king");
        verifyElements("multipleElementsList", multipleElements);

        List<Integer> moreThanElevenElements = ImmutableList.of(1, 2, 3, 4, 5,
                6, 7, 8, 9, 10, 11, 12);
        verifyElements("moreThanElevenElements", moreThanElevenElements);
    }

    private static <T> void verifyElements(String name, List<T> list) {
        System.out.print(name);
        if (list.isEmpty()) {
            System.out.println(" is empty");
        } else {
            System.out.print((list.size() == 1 ? " has one element: " : " has "
                    + list.size() + " elements: "));
            if (list.size() == 1) {
                System.out.println(list.get(0));
            } else {
                list.forEach(new Consumer<T>() {

                    public void accept(T e) {
                        System.out.print(e + " ");
                    }
                });
                System.out.println();
            }
        }
    }
}

Output:

ImmutableList.of() is empty
ImmutableList.of("I am Single") has one element: I am Single
ImmutableList.of("Me", "and you") has 2 elements: Me and you 
multipleElementsList has 8 elements: Once upon time there used to be king 
moreThanElevenElements has 12 elements: 1 2 3 4 5 6 7 8 9 10 11 12 

ImmutableList Creation using copyOf

Consider this scenario: You are providing a library and there is a pubic method with a parameter type of ImmutableList. It may not be convenient for the caller to call your method as they are forced to import ImmutableList class and create an instance of it just to call your method. copyOf method solves this issue as it allows you to create ImmutableList based on array, List, Iterator and Iterable objects. Therefore you can simply use one of these types as the parameter type for your method and internally create an ImmutableList.

ImmutableListCopyOfExample:

package com.javarticles.guava;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;

import com.google.common.collect.ImmutableList;

public class ImmutableListCopyOfExample {
    public static void main(String[] args) {
        Integer[] array = new Integer[] { 1, 2, 3 };
        List<Integer> immutableListCopiedFromArray = ImmutableList
                .copyOf(array);
        verifyElements("immutableListCopiedFromArray",
                immutableListCopiedFromArray);

        List<Integer> list = Arrays.asList(array);
        List<Integer> immutableListCopiedFromList = ImmutableList.copyOf(list);
        verifyElements("immutableListCopiedFromList",
                immutableListCopiedFromList);

        final Iterator<Integer> itr = list.iterator();
        List<Integer> immutableListCopiedFromIterator = ImmutableList
                .copyOf(itr);
        verifyElements("immutableListCopiedFromIterator",
                immutableListCopiedFromIterator);

        Iterable<Integer> iterable = new MyIterable<Integer>(itr);

        List<Integer> immutableListCopiedFromIterable = ImmutableList
                .copyOf(iterable);
        verifyElements("immutableListCopiedFromAlreadyTraversedIterable",
                immutableListCopiedFromIterable);
        verifyElements("immutableListCopiedFromFreshIterable",
                ImmutableList.copyOf(list.iterator()));
    }

    private static class MyIterable<T> implements Iterable<T> {
        private Iterator<T> itr;

        MyIterable(Iterator<T> itr) {
            this.itr = itr;
        }

        public Iterator<T> iterator() {
            return itr;
        }
    }

    private static <T> void verifyElements(String name, List<T> list) {
        System.out.print(name);
        if (list.isEmpty()) {
            System.out.println(" is empty");
        } else {
            System.out.print((list.size() == 1 ? " has one element: " : " has "
                    + list.size() + " elements: "));
            if (list.size() == 1) {
                System.out.println(list.get(0));
            } else {
                list.forEach(new Consumer<T>() {

                    public void accept(T e) {
                        System.out.print(e + " ");
                    }
                });
                System.out.println();
            }
        }
    }
}

If you note statement at line 33, the iterator is already traversed so output will be empty. In the next statement, I use a fresh iterator and and then I am able to print all the elements.

Output:

immutableListCopiedFromArray has 3 elements: 1 2 3 
immutableListCopiedFromList has 3 elements: 1 2 3 
immutableListCopiedFromIterator has 3 elements: 1 2 3 
immutableListCopiedFromAlreadyTraversedIterable is empty
immutableListCopiedFromFreshIterable has 3 elements: 1 2 3 

ImmutableList creation using Builder

You can also create ImmutableList using the static inner class ImmutableList.Builder. This follows builder pattern so you get a very fluent API to build the list using the multiple flavors it supports.

ImmutableListBuilderExample:

package com.javarticles.guava;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;

import com.google.common.collect.ImmutableList;

public class ImmutableListBuilderExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3 });
        ImmutableList.Builder<Integer> builder = ImmutableList.builder();
        ImmutableList<Integer> immutableListFromBuilder = builder
                .add(1)
                .add(2, 3)
                .addAll(list)
                .addAll(list.iterator())
                .addAll(new MyIterable<Integer>(list.iterator()))
                .build();
        verifyElements("immutableListFromBuilder", immutableListFromBuilder);
    }

    private static class MyIterable<T> implements Iterable<T> {
        private Iterator<T> itr;

        MyIterable(Iterator<T> itr) {
            this.itr = itr;
        }

        public Iterator<T> iterator() {
            return itr;
        }
    }

    private static <T> void verifyElements(String name, List<T> list) {
        System.out.print(name);
        if (list.isEmpty()) {
            System.out.println(" is empty");
        } else {
            System.out.print((list.size() == 1 ? " has one element: " : " has "
                    + list.size() + " elements: "));
            if (list.size() == 1) {
                System.out.println(list.get(0));
            } else {
                list.forEach(new Consumer<T>() {

                    public void accept(T e) {
                        System.out.print(e + " ");
                    }
                });
                System.out.println();
            }
        }
    }
}

Output:

immutableListFromBuilder has 12 elements: 1 2 3 1 2 3 1 2 3 1 2 3 

Constraints involved in ImmutableList

What you can’t do with ImmutableList? Its obvious you can’t modify the list. It also doesn’t allow you to add NULL values.

ImmutableListConstraintsExample:

package com.javarticles.guava;

import java.util.List;

import com.google.common.collect.ImmutableList;

public class ImmutableListConstraintsExample {
    public static void main(String[] args) {
        try {
            System.out.println("Try creating ImmutableList with one of the element as null");
            ImmutableList.of("a", null);
        } catch (NullPointerException e) {
            System.out.println("Throws NullPointerException, ImmutableList doesn't allow null elements");
        }
        
        try {
            List list = ImmutableList.of("a");
            System.out.println("Try adding more elements to ImmutableList");
            list.add("b");
        } catch (UnsupportedOperationException e) {
            System.out.println("Throws UnsupportedOperationException, ImmutableList is immutable, won't allow adding elements");
        }
    }
}

Output:

Try creating ImmutableList with one of the element as null
Throws NullPointerException, ImmutableList doesn't allow null elements
Try adding more elements to ImmutableList
Throws UnsupportedOperationException, ImmutableList is immutable, won't allow adding elements

Download source code

This was an example about Guava ImmutableList. You can download the source code here: guavaImmutableListExample.zip

Share.

Comments are closed.