Skip to content

Latest commit

 

History

History
1568 lines (1254 loc) · 56.6 KB

2-Collection_Containers.adoc

File metadata and controls

1568 lines (1254 loc) · 56.6 KB

Collections and containers

What is perhaps most distinctive about the Eclipse Collections collection classes is what (quite properly) is hidden: their implementation of iteration patterns. Through this encapsulation, Eclipse Collections is able to provide optimized versions of each method on each container.

For example, the first of the classes we’ll discuss here, FastList, is array-based; it iterates using indexed access directly against its internal array.

We’ll begin with the Eclipse Collections implementations of types having analogs in the Java Collections Framework (JCF). We’ll then discuss the new types Bag and Multimap, the Immutable collections, and the protective wrapper classes.

Basic collection types

The most commonly-used Eclipse Collections classes are FastList, UnifiedSet, and UnifiedMap. These collections serve as drop-in replacements for their corresponding types in the Java Collections Framework (JCF). Note that these Eclipse Collections classes do not extend the JCF implementations; they are instead new implementations of both JCF and Eclipse Collections interfaces, as this (highly-simplified) diagram summarizes:

Container comparision

The methods of the JCF types are primarily focused on adding or removing elements and similar, non-iterative operations. Eclipse Collections interfaces provide methods for iteration patterns that for the most part, do not modify (mutate) the source collection, but rather return a new collection or information about the source collection.

ListIterable

An ordered collection that allows duplicate elements.

A ListIterable is a RichIterable which maintains its elements in insertion order and allows duplicate elements.

ListIterable has two mutable subinterfaces, MutableList and FixedSizeList, and one immutable subinterface, ImmutableList.

The ListIterable interface includes the binarySearch method, which is similar to the static method binarySearch on java.util.Collections, but available from the object-oriented API.

MutableList

A mutable ListIterable that implements java.util.List; the most common implementation is FastList.

MutableList extends the JCF List interface and has the same contract. It also extends RichIterable, which provides the iteration methods common to all collections.

The most common implementation of MutableList is FastList, which can be used to replace the familiar java.util.ArrayList. Here is a comparison of how the two types can be created.

Example 1. ArrayList in Java Collections Framework
List<String> comparison = new ArrayList<String>();
comparison.add("Comcast");
comparison.add("IBM");
comparison.add("Microsoft");
comparison.add("Microsoft");
Example 2. FastList in Eclipse Collections
MutableList<String> comparison =
    FastList.newListWith("Comcast", "IBM", "Microsoft", "Microsoft");

The MutableList interface includes the sortThis and reverse methods, which are similar to the static methods sort and reverse on java.util.Collections. Both are mutating methods. Here is an example of sort using the JDK API and then Eclipse Collections.

Example 3. ArrayList (JCF) using an anonymous inner class for Comparator
Collections.sort(people, new Comparator<Person>()
{
    public int compare(Person o1, Person o2)
    {
        int lastName = o1.getLastName().compareTo(o2.getLastName());
        if (lastName != 0)
        {
            return lastName;
        }
        return o1.getFirstName().compareTo(o2.getFirstName());
    }
});
Example 4. FastList (EC) using an anonymous inner class for Comparator
people.sortThis(new Comparator<Person>()
{
    public int compare(Person o1, Person o2)
    {
        int lastName = o1.getLastName().compareTo(o2.getLastName());
        if (lastName != 0)
        {
            return lastName;
        }
        return o1.getFirstName().compareTo(o2.getFirstName());
    }
 });
Example 5. FastList (EC) using a lambda
people.sortThis((o1, o2) ->
        {
            int lastName = o1.getLastName().compareTo(o2.getLastName());
            if (lastName != 0)
            {
                return lastName;
            }
            return o1.getFirstName().compareTo(o2.getFirstName());
        });

MutableList adds a new method called sortThisBy, which takes an attribute from each element using a Function and then sorts the list by the natural order of that attribute.

Example 6. ArrayList (JCF) sorting using a static function
Collections.sort(people, Functions.toComparator(Person.TO_AGE));
Example 7. FastList (EC) sorting using a static function
people.sortThisBy(Person.TO_AGE);
Example 8. FastList sorting using a method reference and lambda
// Using a method reference
people.sortThisBy(Person::getAge);

// Using a lambda expression
people.sortThisBy(person -> person.getAge());

Here is an example comparing reverse using the JCF and using Eclipse Collections; both are mutating methods.

Example 9. ArrayList (JCF) reversing a list
Collections.reverse(people);
Example 10. FastList (EC) reversing a list
people.reverseThis();

The toReversed method on MutableList lets you reverse a list without mutating it; that is, it returns a new MutableList. Here is an example of how to accomplish that in the JCF and in Eclipse Collections.

Example 11. ArrayList (JCF) returning a new reversed list
List<Person> reversed = new ArrayList<Person>(people)
Collections.reverse(reversed);
Example 12. FastList (EC) returning a new reversed list
MutableList<Person> reversed = people.toReversed();

The asReversed method returns a reverse-order view of the MutableList —a lazy iterable, like that returned by asLazy —that defers each element’s evaluation until it is called for by a subsequent method.

Example 13. FastList (EC) using lazy evaluation
ListIterable<Integer> integers = FastList.newListWith(1, 2, 3);
// deferred evaluation
LazyIterable<Integer> reversed = integers.asReversed();
// deferred evaluation
LazyIterable<String> strings = reversed.collect(String::valueOf);
// forces evaluation
MutableList<String> stringsList = strings.toList();
 Assert.assertEquals(FastList.newListWith("3", "2", "1"), stringsList);

Migrating ArrayList to FastList

Here are some additional JCF to Eclipse Collections refactoring examples.

Here is a Java Collections' ArrayList:

Example 14. ArrayList (JCF)
List<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(2);
integers.add(3);

And, here is the identical construction in Eclipse Collections:

Example 15. FastList (EC)
List<Integer> integers = new FastList<Integer>();
integers.add(1);
integers.add(2);
integers.add(3);

In Eclipse Collections, the static factory method newList can infer generic types

Example 16. FastList from a newList factory method
List<Integer> integers = FastList.newList();
integers.add(1);
integers.add(2);
integers.add(3);

The Eclipse Collections newListWith() method also provides varargs support, allowing any number of arguments.

Example 17. FastList from a newListwith method
List<Integer> integers = FastList.newListWith(1, 2, 3);

There are also factory classes in Eclipse Collections named for each collection type (Lists, Sets, Maps, Bags, Stacks, BiMaps, Multimaps, etc.)

Example 18. Lists factory classs
List<Integer> integers =
    Lists.mutable.with(1, 2, 3);

You can also use the richer interface:

MutableList<Integer> integers =
    FastList.newListWith(1, 2, 3);

// or

MutableList<Integer> integers =
    Lists.mutable.with(1, 2, 3);

The list is never mutated; it can be made unmodifiable:

Example 19. Unmodifiable FastList
MutableList<Integer> integers =
    FastList.newListWith(1, 2, 3).asUnmodifiable();

There is also a form of newList that takes another iterable.

Example 20. newlist with Iterable as input
MutableList<Integer> integers =
    FastList.newList(listOfIntegers);

These refactorings are analogous for UnifiedSet and UnifiedMap.

SetIterable

A collection that allows no duplicate elements.

A SetIterable is a RichIterable that allows no duplicate elements. It can be sorted or unsorted.

  • A SortedSetIterable is a SetIterable that maintains its elements in sorted order.

  • An UnsortedSetIterable is a SetIterable that maintains its elements in a hash table in an unpredictable order.

UnsortedSetIterable has two mutable subinterfaces (MutableSet and FixedSizeSet) and one immutable subinterface (ImmutableSet).

MutableSet

A mutable SetIterable that implements java.util.Set; the most common implementation is UnifiedSet.

MutableSet extends the JCF Set interface and has the same contract. It also extends RichIterable, which provides the iteration methods common to all collections. An attempt to add duplicate elements to a MutableSet container is ignored without throwing an exception. The order in which the elements are processed during iteration is not specified.

The most common implementation is UnifiedSet, which can be used to replace the familiar java.util.HashSet.

Example 21. HashSet in Java Collections Framework
Set<String> comparison = new HashSet<String>();
comparison.add("IBM");
comparison.add("Microsoft");
comparison.add("Oracle");
comparison.add("Comcast");
Example 22. UnifiedSet in Eclipse Collections
Set<String> comparison = UnifiedSet.newSetWith("IBM", "Microsoft", "Verizon", "Comcast");

MutableSortedSet

Contains unique items that are sorted by some comparator or their natural ordering.

A MutableSortedSet follows the same contract as a MutableSet, but sorts its elements by their natural order, or through a comparator parameter set by the user. The implementation for MutableSortedSet is TreeSortedSet.

Here is an example of a MutableSortedSet containing numbers in reverse order:

Example 23. TreeSortedSet
MutableSortedSet<Integer> sortedSetA =
    TreeSortedSet.newSet(Collections.<Integer>reverseOrder());
MutableSortedSet<Integer> sortedSetB =
    TreeSortedSet.newSet(sortedSetA.with(1).with(2, 3).with(4, 5, 6));

MapIterable

A collection of key/value pairs.

The MapIterable interface (extending RichIterable) is the top-level interface for collections of key/value pairs.

MapIterable has two mutable subinterfaces (MutableMap and FixedSizeMap), one immutable subinterface (ImmutableMap). It is also is extended in mutable and immutable versions of maps with sorted elements (SortedMapIterable) and maps that allow lookup keys by (unique) values as well as the reverse (BiMap).

MutableMap

A mutable MapIterable that implements java.util.Map; the most common implementation is UnifiedMap.

The MutableMap interface defines an association of key/value pairs. It extends the MapIterable interface, which furnishes a set of iteration methods especially for the key/value structure of a Map collection. These include unmodifiable views of keys, values or pair-entries using the keysView, valuesView and entriesView methods, respectively.

The mutable subinterfaces of MapIterable also extend the JCF Map interface.

Example 24. HashMap (JDK)
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "1");
map.put(2, "2");
map.put(3, "3");
Example 25. UnifiedMap (EC)
MutableMap<Integer, String> map = UnifiedMap.newWithKeysValues(1, "1", 2, "2", 3, "3");

MutableSortedMap

A sorted Map.

A MutableSortedMap follows the same contract as a MutableMap, but sorts its elements by their natural order, or through a comparator parameter set by the user. The implementation for MutableSortedMap is TreeSortedMap.

This code block creates a TreeSortedMap which sorts in reverse order:

Example 26. Reversed sorted map
MutableSortedMap<String, Integer> sortedMap = TreeSortedMap.newMapWith(Comparators.<String>reverseNaturalOrder(),
                "1", 1, "2", 3, "3", 2, "4", 1);

BiMap

A map that allows users to add key-value pairs and perform lookups from either direction.

BiMap is an interface that defines a bi-directional Map, i.e, a Map that allows users to execute a lookup from both directions. Both the keys and the values in a BiMap are unique.

BiMap extends MapIterable and MutableBiMap extends MutableMap. The standard implementation is HashBiMap.

Example 27. Bi-directional map
MutableBiMap<Integer, String> biMap =
    HashBiMap.newWithKeysValues(1, "1", 2, "2", 3, "3");

The distinctive methods on MutableBiMap are put, forcePut and inverse.

MutableBiMap.put()

Behaves like put on a regular map, except that it throws an exception when you try to add a duplicate value.

MutableBiMap<Integer, String> biMap = HashBiMap.newMap();
biMap.put(1, "1"); // behaves like a regular put()
biMap.put(1, "1"); // no effect
biMap.put(2, "1"); // throws IllegalArgumentException since value "1" is already present

MutableBiMap.forcePut()

Behaves like MutableBiMap.put, except that it silently removes the map entry with the same value before putting the key-value pair in the map.

MutableBiMap<Integer, String> biMap = HashBiMap.newMap();
biMap.forcePut(1, "1"); // behaves like a regular put()
biMap.forcePut(1, "1"); // no effect
biMap.put(1, "2"); // replaces the [1, "1"] pair with [1, "2"]
biMap.forcePut(2, "2"); // removes the [1, "2"] pair before putting
Assert.assertFalse(biMap.containsKey(1));
Assert.assertEquals(HashBiMap.newWithKeysValues(2, "2"), biMap);

MutableBiMap.inverse()

Returns a reversed view of the BiMap. Calling inverse is an inexpensive operation as the view is already cached in the BiMap. This is the recommend method for looking up the key associated to a value using biMap.inverse().get(value).

MutableBiMap<Integer, String> biMap =
HashBiMap.newWithKeysValues(1, "1", 2, "2", 3, "3");
MutableBiMap<String, Integer> inverse = biMap.inverse();
Assert.assertEquals("1", biMap.get(1));
Assert.assertEquals(Integer.valueOf(1), inverse.get("1"));
Assert.assertTrue(inverse.containsKey("3"));
Assert.assertEquals(Integer.valueOf(2), inverse.put("2", 4));

Bag

An unordered collection that allows duplicates.

A Bag is a RichIterable that allows duplicate elements and efficient querying of the number of occurrences of each element. It can be sorted or unsorted.

  • A SortedBag is a Bag that maintains its elements in sorted order.

  • An UnsortedBag is a Bag that maintains its elements in a hash table in an unpredictable order.

UnsortedBag has two subinterfaces, MutableBag and ImmutableBag. SortedBag has two subinterfaces, MutableSortedBag and ImmutableSortedBag.

A Bag is conceptually like a Map from elements to the number of occurrences of that element.

For example, this list:

Apple
Pear
Orange
Orange
Apple
Orange

could create this Bag:

Pear

1

Orange

3

Apple

2

Example 28. Bag
MutableBag<String> bag =
    HashBag.newBagWith("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");

// or

MutableBag<String> bag =
    Bags.mutable.with("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");

These are the distinctive methods on the Bag interface.

Bag.occurrencesOf(Object item)

Returns the occurrences of a distinct item in the Bag.

Bag.forEachWithOccurrences(ObjIntProcedure)

For each distinct item, with the number of occurrences, executes the specified procedure.

Bag.toMapOfItemToCount()

Returns a map with the item type to its count as an Integer.

MutableBag

A mutable unordered collection allowing duplicates.

The MutableBag interface includes methods for manipulating the number of occurrences of an item. For example, to determine the number of unique elements in a MutableBag, use the sizeDistinct method. The most common implementation of MutableBag is HashBag.

Example 29. MutableBag
MutableBag<String> bag = HashBag.newBagWith("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");

// or

MutableBag<String> bag = Bags.mutable.with("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");

These are the distinctive methods on MutableBag:

MutableBag.addOccurrences(T item, int occurrences)

Increments the count of the item in the bag by a count specified by occurrences.

MutableBag.removeOccurrences(Object item, int occurrences)

Decrements the count of the item in the bag by a count specified by occurrences.

MutableBag.setOccurrences(T item, int occurrences)

Mutates the bag to contain the specified number of occurrences of the item.

MutableSortedBag

A sorted collection that allows duplicates.

A MutableSortedBag is a Bagthat maintains order. It defaults to natural order, but can take a comparator to sort. The most common implementation of MutableSortedBag is TreeBag which uses a SortedMap as its underlying data store.

For example, this MutableSortedBag would contain integers sorted in reverse order:

Example 30. EC
MutableSortedBag<Integer> revIntegers =
    TreeBag.newBagWith(Collections.reverseOrder(), 4, 3, 3, 2, 2, 2, 1, 1);

// or

MutableSortedBag<Integer> revIntegers =
    SortedBags.mutable.with(Collections.reverseOrder(), 4, 3, 3, 2, 2, 2, 1, 1);

StackIterable

A collection that maintains "last-in, first-out" order, iterating over elements in reverse insertion order.

A StackIterable is a RichIterable enforcing a "last-in, first-out" order; its methods always iterate over elements in reverse insertion order, (beginning with the most-recently added element). For example the getFirst method returns the the last element to have been added - the "top" of the stack.

StackIterable has a mutable and an immutable subinterface MutableStack and ImmutableStack, respectively.

MutableStack

A mutable collection that maintains "last-in, first-out" order, iterating over elements in reverse insertion order.

The most common implementation of MutableStack is ArrayStack. The closest JCF equivalent to ArrayStack is java.util.Stack, which extends Vector but does not enforce strict LIFO iteration.

The distinctive methods on MutableStack are push, pop, and peek.

push

Adds a new element to the top of the stack

pop

Returns the top (most recently-added) element and removes it from the collection.

pop(int count)

Returns a ListIterable of the number of elements specified by the count, beginning with the top of the stack.

peek

Returns but does not remove the top element. Note that, on a stack, getFirst likewise returns the top element, and that getLast throws an exception.

peek(int count)

Returns a ListIterable of the number of elements specified by the count, beginning with the top of the stack; does not remove the elements from the stack.

peekAt(int index)

Returns the element at index.

ArrayStack can replace java.util.Stack.

Example 31. Stack in Java Collections Framework
Stack stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
Example 32. ArrayStack in Eclipse Collections
MutableStack mutableStack =
    ArrayStack.newStackWith(1, 2, 3);

// or

MutableStack mutableStack =
    Stacks.mutable.with(1, 2, 3);

Multimap

A map-like container that can have multiple values for each key

In a Multimap container, each key can be associated with multiple values. It is, in this sense, similar to a Map, but one whose values consist of individual collections of a specified type, called the backing collection. A Multimap is useful in situations where you would otherwise use Map<K, Collection<V>>.

Unlike the other basic Eclipse Collections containers, Multimap does not extend RichIterable, but resides along with its subinterfaces in a separate API. The RichIterable methods are extended by the backing collection types.

Depending on the implementation, the "values" in a Multimap can be stored in Lists, Sets or Bags. For example, the FastListMultimap class is backed by a UnifiedMap that associates each key with a FastList that preserves the order in which the values are added and allows duplicate to be added.

A Multimap is the type returned by the groupBy method. Here is an example in which we group a list of words by their length, obtaining a Multimap with integer (word=length) keys and lists of words having that length for values.

This simple list:

   here
   are
   a
   few
   words
   that
   are
   not
   too
   long

produces a List-backed Multimap:

key value<list>

1

a

3

are, few, are, not, too

4

here, that, long

5

words

The code that performs this action uses the groupBy method.

Example 33. MutableListMultimap using groupBy with StringFunctions)
MutableList<String> words = Lists.mutable.with("here", "are", "a", "few",
     "words", "that", "are", "not", "too", "long");
MutableListMultimap<Integer, String> multimap =
    words.groupBy(StringFunctions.length());
Example 34. MutableListMultimap using groupBy with a method reference
MutableList<String> words = Lists.mutable.with("here", "are", "a", "few",
     "words", "that", "are", "not", "too", "long");
MutableListMultimap<Integer, String> multimap =
    words.groupBy(String::length);

The interface MutableListMultimap extends the Multimap interface and tells us the type of its backing collections. Since words is a MutableList, the output is a MutableListMultimap. The word "are" is allowed to occur twice in the list at key 3.

If we change words to a MutableSet, the result will be a MutableSetMultimap, which will eliminate duplicate entries.

Example 35. MutableSetMultimap using groupBy with StringFunctions
MutableSet<String> words = Sets.mutable.with("here", "are", "a", "few",
     "words", "that", "are", "not", "too", "long");
MutableSetMultimap<Integer, String> multimap =
    words.groupBy(StringFunctions.length());
Example 36. MutableSetMultimap using groupBy with a method reference
MutableSet<String> words = Sets.mutable.with("here", "are", "a", "few",
     "words", "that", "are", "not", "too", "long");
MutableSetMultimap<Integer, String> multimap =
    words.groupBy(String::length);

With duplicates removed, only four 3-letter words remain.

key value <list>

1

a

3

too,are,few,not,

4

long,here,that

5

words

Primitive collections

Containers for iterating over collections of Java primitives.

Eclipse Collections has memory-optimized lists, sets, stacks, maps, and bags for all the primitive types: int, long, float, char, byte, boolean, short, and double.

The interface hierarchies for primitive types correspond closely with the interface hierarchy for regular Object collections. For example, the collection interfaces for int include the following:

interface

analogous to

IntIterable

RichIterable

MutableIntCollection

MutableCollection

IntList

ListIterable

MutableIntList

MutableList

There are some common arithmetic operations that can be performed on all primitive collections (except boolean collections).

Example 37. Mathematical operations on primitive collections
MutableIntList intList = IntLists.mutable.with(1, 2, 3);
Assert.assertEquals(6, intList.sum());
Assert.assertEquals(1, intList.min());
Assert.assertEquals(3, intList.max());
Assert.assertEquals(2.0d, intList.average(), 0.0);
Assert.assertEquals(2, intList.median());

// IntList.summaryStatistics() returns IntSummaryStatistics
Assert.assertEquals(6, intList.summaryStatistics().getSum());
Assert.assertEquals(1, intList.summaryStatistics().getMin());
Assert.assertEquals(3, intList.summaryStatistics().getMax());
Assert.assertEquals(2.0d, intList.summaryStatistics().getAverage(), 0.0);

Primitive lists

The primitive list implementations are backed by an array like FastList, but with a primitive array instead of an Object[]. They are named IntArrayList, FloatArrayList etc.

BooleanArrayList is a special case. Current JVMs use one byte per boolean in a boolean[] (instead of one bit per boolean). Thus the BooleanArrayList is backed by a java.util.BitSet as an optimization.

Example 38. our ways to create an IntArrayList, use one of the following:
IntArrayList emptyList = new IntArrayList();
IntArrayList intList = IntArrayList.newListWith(1, 2, 3);
IntArrayList alternate = IntLists.mutable.with(1, 2, 3);
IntArrayList listFromIntIterable = IntArrayList.newListWith(IntHashSet.newSetWith(1, 2, 3));

IntInterval

An IntInterval is a range of ints that may be iterated over using a step value. (Similar to Interval, but uses primitive ints instead of the wrapper Integers.) All arguments are inclusive in methods of IntInterval.

As IntInterval implements ImmutableIntList, you can pass it in any method or constructor argument which accept ImmutableIntList.

Assertions.assertInstanceOf(ImmutableIntList.class, IntInterval.oneTo(5));
There are different ways you can generate interval of numbers using IntInterval, which are listed below.
  • You can initialize IntInterval using constructor argument which accept from, to and steps.

  • You can initialize IntInterval using static factory methods.

// Generate interval of numbers from 1 to 5, with the default step value of 1
ImmutableIntList expected = IntLists.immutable.with(1, 2, 3, 4, 5);
Assertions.assertEquals(expected, IntInterval.fromTo(1, 5));

// Generate interval of numbers from 1 to 10, with providing steps value as method argument
ImmutableIntList expected = IntLists.immutable.with(1, 4, 7, 10);
Assertions.assertEquals(expected, IntInterval.fromToBy(1, 10, 3));

// from method is used to generate interval with only one number which is provided as method argument
ImmutableIntList expected = IntLists.immutable.with(10);
Assertions.assertEquals(expected, IntInterval.from(10));

// Generate interval of even numbers, here steps value can be 2 or -2, based on following condition [to > from ? 2 : -2]
ImmutableIntList expected = IntLists.immutable.with(2, 4, 6);
Assertions.assertEquals(expected, IntInterval.evensFromTo(2, 6));

ImmutableIntList expected = IntLists.immutable.with(6, 4, 2);
Assertions.assertEquals(expected, IntInterval.evensFromTo(6, 2));

// Generate interval of odd numbers, here steps value can be 2 or -2, based on following condition [to > from ? 2 : -2]
ImmutableIntList expected = IntLists.immutable.with(1, 3, 5);
Assertions.assertEquals(expected, IntInterval.oddsFromTo(1, 5));

ImmutableIntList expected = IntLists.immutable.with(5, 3, 1);
Assertions.assertEquals(expected, IntInterval.oddsFromTo(5, 1));

// Generate interval of numbers from 1 to 5, with the default step value of 1
ImmutableIntList expected = IntLists.immutable.with(1, 2, 3, 4, 5);
Assertions.assertEquals(expected, IntInterval.oneTo(5));

// Generate interval of numbers from 1 to 9, with providing step value as a method argument
ImmutableIntList expected = IntLists.immutable.with(1, 3, 5, 7, 9);
Assertions.assertEquals(expected, IntInterval.oneToBy(10, 2));

// zero is used to create interval with only one number [0]
ImmutableIntList expected = IntLists.immutable.with(0);
Assertions.assertEquals(expected, IntInterval.zero());

// Generate interval of numbers from 0 to 4, with the default step value of 1
ImmutableIntList expected = IntLists.immutable.with(0, 1, 2, 3, 4);
Assertions.assertEquals(expected, IntInterval.zeroTo(4));

// Generate interval of numbers from 0 to 4, with providing step value as a method argument
ImmutableIntList expected = IntLists.immutable.with(0, 2, 4);
Assertions.assertEquals(expected, IntInterval.zeroToBy(4, 2));

Primitive sets

The primitive set implementations are hash-table backed. They are named IntHashSet, FloatHashSet, etc. BooleanHashSet is implemented using a single integer to hold one of four possible states: ([], [F], [T], or [T, F]). All other sets use open addressing and quadratic probing.

There are different ways you can create primitive sets, which are listed below.
  • You can create primitive sets using newSetWith method.

  • You can initialize primitive sets using constructor argument. There are several overloaded constructors available. Below examples are provided with IntHashSet but all are same for FloatHashSet and BooleanHashSet as well.

  • There is another way to construct primitive types using primitive factory classes.

// Initialize IntHashSet using newSetWith method, which is taking int vargs.
MutableIntSet intHashSet1 = IntHashSet.newSetWith(1, 2, 3, 4, 5);
MutableFloatSet floatHashSet1 = FloatHashSet.newSetWith(12.5f, 13.5f, 14.88f, 15.6f);
MutableBooleanSet booleanHashSet = BooleanHashSet.newSetWith(true, false);

// Empty Constructor will initialize IntHashSet with 16 size
MutableIntSet intHashSet2 = new IntHashSet();

// Initialize Constructor with initialCapacity
MutableIntSet intHashSet3 = new IntHashSet(32);

// Initialize Constructor with set of integers using vargs.
MutableIntSet intHashSet4 = new IntHashSet(1, 2, 3, 4, 5, 6);

// Initialize Constructor with IntIterable.
IntIterable intIterable = intHashSet4; // you can get from any list, set which implement this interface
MutableIntSet intHashSet = new IntHashSet(intIterable);

// Initialize Constructor with existing IntHashSet
MutableIntSet intHashSet5 = new IntHashSet(intHashSet2);

Primitive sets can be created using factory classes. IntSets, FloatSets and BooleanSets are primitive factory classes that provide mutable & immutable ways of creating sets. Factory classes provide different sets of methods for creating sets like with, withAll, empty and ofAll, with different sets of arguments. Provided examples are with IntSets but all are valid for FloatSets and BooleanSets as well.

withInitialCapacity is only available in mutable factories.

// mutable intset creation using initialCapacity
MutableIntSet mutableIntSetCapacity = IntSets.mutable.withInitialCapacity(12);
mutableIntSetCapacity.addAll(1, 3, 5, 6);

// mutable sets creation using factory class using with method.
MutableIntSet mutableIntSet = IntSets.mutable.with(1, 2, 3, 4, 5);
MutableFloatSet mutableFloatSet = FloatSets.mutable.with(1.5f, 2.5f);
MutableBooleanSet mutableBooleanSet = BooleanSets.mutable.with(true, false, false, true);

// Immutable sets creation using factory class using with method.
ImmutableIntSet immutableIntSet = IntSets.immutable.with(1, 2, 3, 4, 5);
ImmutableFloatSet immutableFloatSet = FloatSets.immutable.with(1.5f, 2.5f);
ImmutableBooleanSet immutableBooleanSet = BooleanSets.immutable.with(true, false, false, true);

// immutable intset creating using IntIterable
IntIterable intIterable = immutableIntSet; // you can get from any list, set which implement this interface
ImmutableIntSet immutableIntSet = IntSets.immutable.withAll(intIterable);

Operation which you can perform on primitive hashsets.

// Initialize IntHashSet using newSetWith method, which is taking int vargs.
MutableIntSet intHashSet = IntHashSet.newSetWith(1, 2, 3, 4, 5);
intHashSet.add(6);
intHashSet.addAll(7, 8, 9); //addAll takes varags argument

// We can use allSatisfy/anySatisfy method which take predicate to compare with all value of primitive sets
boolean allSatisfy = intHashSet.allSatisfy(x -> 2 < x);
boolean anySatisfy = intHashSet.anySatisfy(x -> 5 > x);

// containsAll check for all element in primitive set
boolean containsAll = intHashSet.containsAll(5, 4);

// We can do a math operation like min, max on intHashSet
int min = intHashSet.min();
int max = intHashSet.max();

// We can filter set with select method, which return filtered set, same way you can use reject as well
MutableIntSet evens = intHashSet.select(x -> 0 == x % 2);
MutableIntSet odds = intHashSet.reject(x -> 0 == x % 2);

// We can do different set of conversion operation on primitive set as well, like toArray, toSortedArray, toBag, toSortedList and many more.
ImmutableIntSet immutableIntSet = intHashSet.toImmutable();
int[] toArray = intHashSet.toArray();
int[] toSortedArray = intHashSet.toSortedArray();
MutableIntList mutableIntList = intHashSet.toSortedList();
MutableIntBag mutableIntBag = intHashSet.toBag();

Primitive stacks

Primitive stack implementations are similar to JCF ArrayStack but optimized for primitives.

Primitive bags

Primitive bag implementations are similar to JCF HashBag, but both item and count are primitives.

Primitive Maps

There are three types of primitive maps:

All the maps use open addressing and quadratic probing.

Primitive maps with numeric value types (not boolean or Object) have a method addToValue that adds the given amount to the value at the given key and returns the updated value.

Example 39. addToValue
MutableByteIntMap map = new ByteIntHashMap();
Assert.assertEquals(1, map.addToValue((byte) 0, 1));
Assert.assertEquals(ByteIntHashMap.newWithKeysValues((byte) 0, 1), map);
Assert.assertEquals(11, map.addToValue((byte) 0, 10));
Assert.assertEquals(ByteIntHashMap.newWithKeysValues((byte) 0, 11), map);

All primitive collections have immutable counterparts, and unmodifiable and synchronized wrappers. See the Protecting collections topic for more information.

Immutable collections

A read-only snapshot of a collection; once created, it can never be modified.

All of the basic containers in Eclipse Collections have interfaces for both mutable and immutable (unchangeable) forms. This departs somewhat from the model of the Java Collections Framework, in which most containers are mutable.

An immutable collection is just that - once created, it can never be modified, retaining the same internal references and data throughout its lifespan. An immutable collection is equal to a corresponding mutable collection with the same contents; a MutableList and an ImmutableList can be equal.

Because its state does not change over time, an immutable collection is always thread-safe. Using immutable collections where feasible can serve to make your code easier to read and understand.

All of the interfaces and implementations discussed so far in this topic have been mutable versions of their respective types. Each of these containers has an immutable counterpart. These are the corresponding interfaces:

Mutable types

Immutable types

MutableList

ImmutableList

MutableSet

ImmutableSet

MutableBag

ImmutableBag

MutableMap

ImmutableMap

MutableMultimap

ImmutableMultimap

MutableStack

ImmutableStack

The method that returns an immutable collection for all container types is toImmutable():

MutableCollection.toImmutable(): ImmutableCollection

Returns an immutable copy of a type corresponding to the source MutableCollection.

StackIterable.toImmutable(): ImmutableStack

Returns an immutable copy of a MutableStack, returns the same iterable for an ImmutableStack.

ListIterable.toImmutable(): ImmutableList

Returns an immutable copy of a MutableList, returns the same iterable for an ImmutableList.

SortedMapIterable.toImmutable(): ImmutableSortedMap

Returns an immutable copy of a MutableSortedMap, returns the same iterable for an ImmutableSortedMap.

UnsortedMapIterable.toImmutable(): ImmutableMap

Returns an immutable copy of a MutableMap, returns the same iterable for an ImmutableMap.

An immutable-collection interface lacks mutating methods, such as add and remove. Instead, immutable collections have methods that return new, immutable copies with or without specified elements:

ImmutableCollection. newWith(element): ImmutableCollection

Returns a new immutable copy of ImmutableCollection with element added.

ImmutableCollection. newWithAll(Iterable): ImmutableCollection

Returns a new immutable copy of ImmutableCollection with the elements of Iterable added.

ImmutableCollection. newWithout(element): ImmutableCollection

Returns a new immutable copy of ImmutableCollection with element removed.

ImmutableCollection. newWithoutAll(Iterable): ImmutableCollection

Returns a new immutable copy of ImmutableCollection with the elements of Iterable removed.

Note that the iteration methods of an immutable container - such as select, reject, and collect - also produce new immutable collections.

Immutable collection factory classes

The factory classes Lists, Sets, Bags, and Maps create immutable collections. These factories also provide methods for creating fixed-size collections, which have been superseded by immutable collections.

Example 40. Factory classes for immutable collections
ImmutableList<Integer> immutableList = Lists.immutable.of(1, 2, 3);
ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3);
Bag<Integer> immutableBag = Bags.immutable.of(1, 2, 2, 3);
ImmutableMap<Integer, String> immutableMap =
    Maps.immutable.of(1, "one", 2, "two", 3, "three");

These factories highlight yet another benefit of immutable collections: they let you create efficient containers that are sized according to their contents. In cases where there are many, even millions of collections, each with a size less than 10, this is an important advantage.

Growing and shrinking immutable collections

There are no mutating methods like add(), addAll(), remove() or removeAll() on immutable collection interfaces in Eclipse Collections. However, we may want to add or remove elements. Methods like newWith(), newWithout(), newWithAll() and newWithoutAll() allow for safe copying of immutable collections. For ImmutableMap implementations, the methods are named newWithKeyValue(), newWithAllKeyValues(), newWithoutKey() and newWithoutAllKeys().

Example 41. Add elements to an immutable list
// persons is an mutable list: MutableList<Person> persons
// Person is a class with attributes name, age and address

PartitionMutableList<Person> partitionedFolks =
        persons.partition(person -> person.getAge() >= 18); // defines a partition pattern

ImmutableList<Person> list0 = Lists.immutable.empty();
ImmutableList<Person> list1 = list0.newWith(new Person(...)); // add a single element to the new immutable list
ImmutableList<Person> adults = list1.newWithAll(partitionedFolks.getSelected()); // add none, one or more objects to the new immutable list

ImmutableSet<String> set0 = Sets.immutable.empty();
ImmutableSet<String> set1 = set0.newWith("1"); // add a single element to the new immutable set
ImmutableSet<String> set2 = set1.newWithAll(Sets.mutable.with("2")); // add none, one or more objects to the new immutable set

For ImmutableMap implementations, the methods are named newWithKeyValue(), newWithAllKeyValues(), newWithoutKey(} and newWithoutAllKeys().

Example 42. Add elements to an immutable map
ImmutableMap<String, String> map0 = Maps.immutable.empty();
ImmutableMap<String, String> map1 = map0.newWithKeyValue("1", "1");
ImmutableMap<String, String> map2 = map1.newWithAllKeyValues(Lists.mutable.with(Tuples.pair("2", "2")))

These methods are available on the primitive containers too though we are missing some symmetry in our immutable primitive map containers. We do not currently have newWithAllKeyValues() on immutable primitive maps. The corresponding feature request is here.

Example 43. Immutable primitive containers
ImmutableIntList list0 = IntLists.immutable.empty();
ImmutableIntList list1 = list0.newWith(1);
ImmutableIntList list2 = list1.newWithAll(IntLists.mutable.with(2));

ImmutableIntSet set0 = IntSets.immutable.empty();
ImmutableIntSet set1 = set0.newWith(1);
ImmutableIntSet set2 = set1.newWithAll(IntSets.mutable.with(2));

ImmutableIntIntMap map0 = IntIntMaps.immutable.empty();
ImmutableIntIntMap map1 = map0.newWithKeyValue(1, 1);

Creating collection containers

Eclipse Collections has many iteration methods that return new collection containers from existing ones. These include the select and collect methods, along with their specialized variants, such as partition and groupBy. There are also multiple ways to instantiate new containers, from scratch or by conversion from other container types.

Creating mutable collections

If you know the implementation class of the container (for example, FastList or UnifiedSet), you can use either of these two techniques:

  • Call the class constructor; for example, FastList<String> names = new FastList;

  • Call a factory method on the collection class, such as newList or newListWith; for example, MutableList<V> result = FastList.newList(this.size);

If, however, the specific collection class to implement is unknown, you can call a factory class to create the container. Eclipse Collections container-factory classes are named for the plural of the respective container name. For example, for a List, the factory class is Lists; a Set is created by the class Sets.

You can specify the content and mutable state of the container in parameters. This approach to container creation, when used consistently, has the added benefit of being more readable.

Example 44. Container factory classes
MutableList<String> emptyList = Lists.mutable.empty();  // creates an empty list
MutableList<String> list = Lists.mutable.with("a", "b", "c"); // creates a list of elements a,b,c
MutableList<String> list_a = Lists.mutable.of("a", "b", "c"); // creates a list of elements a,b,c
MutableSet<String> emptySet = Sets.mutable.empty();
// creates an empty set
MutableSet<String> set = Sets.mutable.with("a", "b", "c"); // creates a set of elements a,b,c
MutableSet<String> set_a = Sets.mutable.of("a", "b", "c"); // creates a set of elements a,b,c
MutableBag<String> emptyBag= Bags.mutable.empty();
// creates an empty bag
MutableBag<String> bag = Bags.mutable.with("a", "b", "c"); // creates a bag of elements a,b,c
MutableBag<String> bag_a = Bags.mutable.of("a", "b", "c"); // creates a bag of elements a,b,c

Container

Factory

List

Lists

Set

Sets, HashingStrategySets

Bag

Bags

Stack

Stacks

SortedBag

SortedBags

SortedSet

SortedSets

Map

Maps, HashingStrategyMaps

SortedMap

SortedMaps

BiMap

BiMaps

Multimap

Multimaps

You can also create a mutable container from a instance of the same type:

newEmpty() : MutableCollection

Creates a new, empty, and mutable container of the same collection type. For example, if this instance is a FastList, this method will return a new empty FastList. If the class of this instance is immutable or fixed size (for example, a singleton List) then a mutable alternative to the class is returned.

Creating immutable collections

There are two ways to create an immutable List, Set, Bag, Stack or Map.

  • Create a mutable version of a container type (as described in the previous section), and then call toImmutable() on the result to create an immutable copy.

  • Use factory classes to create immutable versions of classes.

Example 45. Create an immutable container by calling toImmutable()
ImmutableList<String> list =
    Lists.mutable.with("a", "b", "c").toImmutable(); // creates a list of elements a,b,c
ImmutableSet<String> set0 =
    Lists.mutable.with("a", "b", "a", "c").toSet().toImmutable(); // creates a set of elements a,b,c
ImmutableSet<String> set1 =
    Sets.mutable.with("a", "b", "a", "c").toImmutable(); // creates a set of elements a,b,c
ImmutableMap<Integer, String> map =
    Maps.mutable.with(1, "a", 2, "b", 3, "c").toImmutable(); // creates a map with keys 1,2,3
Example 46. Create an immutable container using factory classes
ImmutableList<String> emptyList_i =
    Lists.immutable.empty();  // creates an empty list
ImmutableList<String> list_b =
    Lists.immutable.with("a", "b", "c"); // creates a list of elements a,b,c
ImmutableList<String> list_c =
    Lists.immutable.of("a", "b", "c");  // creates a list of elements a,b,c

ImmutableSet<String> emptySet_i =
    Sets.immutable.empty();  // creates an empty Set
ImmutableSet<String> set_b =
    Sets.immutable.with("a", "b", "c"); // creates a Set of elements a,b,c
ImmutableSet<String> set_c =
    Sets.immutable.of("a", "b", "c");  // creates a Set of elements a,b,c

ImmutableMap<Integer, String> emptyMap_i =
    Maps.immutable.empty(); // creates an empty map
ImmutableMap<Integer, String> map_b =
    Maps.immutable.with(1, "a", 2, "b", 3, "c"); // creates a map with keys 1,2,3
ImmutableMap<Integer, String> map_c =
    Maps.immutable.of(1, "a", 2, "b", 3, "c"); // creates a map with keys 1,2,3

Creating primitive collections

The techniques for creating mutable or immutable primitive containers are the same as those for object collections.

  • If you know the implementation class, you can call its constructor or its factory method.

  • Otherwise use the applicable factory class named for the plural of the type, that is, with the pattern: primitivetype >< containertype >s. For example, to create an IntList, you would use the IntLists factory for the appropriate methods; for a DoubleSet, you would call in methods in DoubleSets.

Example 47. Create an immutable primitive class using a factory
MutableIntList emptyList_pm =
    IntLists.mutable.empty();       // creates an empty list
MutableIntList list_d =
    IntLists.mutable.with(1, 2, 3); // creates a list of elements a,b,c
MutableIntList list_e =
    IntLists.mutable.of(1, 2, 3);   // creates a list of elements a,b,c
ImmutableIntList emptyList_pi =
    IntLists.immutable.empty();     // creates an empty list
ImmutableIntList list_f =
    IntLists.immutable.with(1, 2, 3); // creates a list of elements a,b,c
ImmutableIntList list_g =
    IntLists.immutable.of(1, 2, 3); // creates a list of elements a,b,c
type \ container List Set Bag Stack

boolean

BooleanLists

BooleanSets

BooleanBags

BooleanStacks

byte

ByteLists

ByteSets

ByteBags

ByteStacks

char

CharLists

CharSets

CharBags

CharStacks

short

ShortLists

ShortSets

ShortBags

ShortStacks

int

IntLists

IntSets

IntBags

IntStacks

float

FloatLists

FloatSets

FloatBags

FloatStacks

long

LongLists

LongSets

LongBags

LongStacks

double

DoubleLists

DoubleSets

DoubleBags

DoubleStacks

Converting collections

The following methods can be used to convert one container type to another. All of these methods are on RichIterable. To create immutable and fixed-size collections, see Immutable collections.

toList() : MutableList

Converts the collection to the default MutableList implementation (FastList).

toSet() : MutableSet

Converts the collection to the default MutableSet implementation (UnifiedSet).

toBag() : MutableBag

Converts the collection to the default MutableBag implementation (HashBag).

toMap(keyFunction, valueFunction): MutableMap

Converts the collection to the default MutableMap implementation (UnifiedMap) using the specified keyFunctions and valueFunctions.

toSortedList() : MutableList

Converts the collection to the default MutableList implementation (FastList) and sorts it using the natural order of the elements.

toSortedList(Comparator) : MutableList

Converts the collection to the default MutableList implementation (FastList) and sorts it using the specified Comparator.

These methods always return new mutable copies: for example, calling toList on a FastList, returns a new FastList.

Protective wrappers

Wrapper classes providing read-only or thread-safe views of a collection.

Unmodifiable collections

In both the JCF and Eclipse Collections, a collection may be rendered unmodifiable. In Eclipse Collections, this is done by means of the asUnmodifiable method, which returns a read-only view of the calling collection. This means that the mutating methods of the collection (e.g., add, remove) are still present, but throw exceptions if called.

MutableCollection. asUnmodifiable(): MutableCollection (read-only)

Returns a read-only view of the source collection.

MutableIntCollection.asUnmodifiable(): MutableIntCollection.(read-only)

Returns a read-only view of the source primitive collection. There are similar methods for each primitive type, e.g., MutableFloatCollection.asUnmodifiable()

Synchronized collections

Eclipse Collections provides a wrapper for rendering a modifiable but thread-safe view that holds a lock when a method is called and releases the lock upon completion.

MutableCollection. asSynchronized(): MutableCollection

Returns a synchronized copy of the source collection.

MutableIntCollection. asSynchronized(): MutableIntCollection.

Returns a synchronized copy of the source primitive collection. There are similar methods for each primitive type, e.g., MutableFloatCollection.asSynchronized().

previous: Iteration patterns

top

next: Code blocks