Skip to content

Latest commit

 

History

History
2185 lines (1760 loc) · 68.3 KB

1-Iteration_Patterns.adoc

File metadata and controls

2185 lines (1760 loc) · 68.3 KB

Iteration patterns

Eclipse Collections extends the Java Collections Framework with new interfaces and classes and provides additional methods. These new methods implement iteration patterns derived from the collection protocols of the Smalltalk language (e.g., select, reject, collect, detect, injectInto).

In idiomatic (imperative) Java code, iteration is performed by external for and while loops that enclose a block of business logic to be performed on each element of a collection. This is an approach that often leads to much code duplication.

In Eclipse Collections, business logic is reified as a code block: a class that is passed as a parameter to an iteration method. Each implementation of an iteration method iterates over the collection, passing each element to the code block for processing. In Java 8, these code blocks can be specified using the lambda and method reference syntax.

The most important advantage of internal iteration patterns is that they increase readability by giving names to the structural iteration patterns and by reducing code duplication. Moreover, by encapsulating implementation within specialized collection types (e.g., list, sets, maps), iteration can be optimized for the particular type.

Common iteration patterns

These are the most commonly-used iteration patterns in Eclipse Collections.

Filtering patterns
Select
Reject
Partition

Transforming patterns
Collect
FlatCollect
GroupBy

Fused patterns
CollectIf
CountBy
ContainsBy

"Short-circuit" patterns
Detect
DetectIfNone
AnySatisfy
AllSatisfy
NoneSatisfy

Generic action patterns
ForEach
InjectInt

Select and Reject patterns

Filter a collection to create a new collection: includes select, reject, and partition.

Methods using the Select pattern return a new collection comprising those elements from the source collection that satisfy some logical condition. Reject is the inverse pattern, returning a new collection of elements that do not satisfy the condition. The condition is a boolean expression in the form of single-argument code block that implements the Predicate interface.

Select pattern examples

Example 1. Select pattern (pseudocode)
create <newCollection>
 for each <element> of <collection>
     if condition(<element>)
         add <element> to <newCollection>
Example 2. Select using a lambda expression
MutableList<Integer> greaterThanFifty = list.select(each -> each > 50);
Example 3. Select using an anonymous inner class as a code block
MutableList<Integer> greaterThanFifty =
    list.select(new Predicate<Integer>()
    {
        public boolean accept(Integer each)
        {
            return each > 50;
        }
    });
Example 4. Creating a select Predicate using the Predicates factory
MutableList<Integer> greaterThanFifty = list.select(Predicates.greaterThan(50));
Example 5. Select in Java 8+ Streams using Collectors2
MutableList<Integer> greaterThanFifty = list.stream()
    .collect(Collectors2.select(each -> each.intValue() > 50, Lists.mutable::empty));
Example 6. Select pattern in imperative Java
List<Integer> greaterThanFifty = Lists.mutable.empty();
for (Integer each : list)
{
    if (each.intValue() > 50)
    {
        greaterThanFifty.add(each);
    }
}

Reject pattern examples

Example 7. Reject pattern (pseudocode)
create <newCollection>
 for each <element> of <collection>
     if not condition(<element>)
         add <element> to <newCollection>
Example 8. Reject using a lambda expression
MutableList<Integer> notGreaterThanFifty =
    list.reject(each -> each > 50);
Example 9. Reject Predicate using the Predicates factory
MutableList<Integer> notGreaterThanFifty = list.reject(Predicates.greaterThan(50));
Example 10. Reject in Java 8+ Streams using Collectors2
MutableList<Integer> notGreaterThanFifty = list.stream()
    .collect(Collectors2.reject(each -> each.intValue() > 50, Lists.mutable::empty));
Example 11. Reject pattern in imperative Java
List<Integer> notGreaterThanFifty = Lists.mutable.empty();
for (Integer each : list)
{
    if (each <= 50)
    {
        notGreaterThanFifty.add(each);
    }
}

Select and Reject methods

These Eclipse Collections methods implement the Select and Reject pattern:

select(Predicate): RichIterable
reject(Predicate): RichIterable

The Predicate is evaluated for each element of the collection. The selected elements are those where the Predicate returned true (false for rejected). The selected (or rejected) elements are returned in a new collection of the same type.

select(Predicate, targetCollection): targetCollection
reject(Predicate, targetCollection): targetCollection

Same as the select/reject methods with one argument, but results are added to the specified targetCollection.

selectWith(Predicate2, argument): RichIterable
rejectWith(Predicate2, argument): RichIterable

For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additional argument; selected or rejected elements are returned in a new collection of the same type. See Reusing code blocks for more information.

selectWith(Predicate2, argumenttargetCollection): targetCollection
rejectWith(Predicate2, argumenttargetCollection): targetCollection

Same as the selectWith/rejectWith methods, but results are added to the specified targetCollection.

Partition pattern

Create two collections using Select and Reject.

The Partition pattern allocates each element of a collection into one of two new collections depending on whether the element satisfies the condition expressed by the Predicate. In effect, it combines the Select and Reject patterns. The collections are returned in a PartitionIterable specialized for the type of the source collection. You can retrieve the selected and rejected elements from the PartitionIterable. In this example, the list of people is partitioned into lists of adults and children.

Example 12. Partition using a lambda expression
PartitionMutableList<Person> partitionedFolks =
    people.partition(person -> person.getAge() >= 18);
MutableList<Person> adults = partitionedFolks.getSelected();
MutableList<Person> children = partitionedFolks.getRejected();
Example 13. Partition using an anonymous inner class
MutableList<Person> people =...
PartitionMutableList<Person> partitionedFolks = people.partition(
    new Predicate<Person>()
    {
        public boolean accept(Person each)
        {
            return each.getAge() >= 18;
        }
    });
MutableList<Person> adults = partitionedFolks.getSelected();
MutableList<Person> children = partitionedFolks.getRejected();
Example 14. Java 8 Streams using Collectors2.partition
List<Person> people =...
PartitionMutableList<Person>> partitionedFolks = people.stream()
    .collect(Collectors2.partition(person -> person.getAge() >= 18, PartitionFastList::new)
MutableList<Person> adults = partitionedFolks.getSelected();
MutableList<Person> children = partitionedFolks.getRejected());

Partition methods

These Eclipse Collections methods implement the partition pattern:

partition(Predicate): PartitionIterable

Returns a PartitionIterable, a logical pair of containers. The first container consists of all elements that satisfy the Predicate. The second container consists of all elements that do not satisfy the Predicate. The subtypes of PartitionIterable correspond with the subtypes of RichIterable.

partitionWith(Predicate2, argument): PartitionIterable

For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additional argument; partitioned elements are returned in a new collection of type PartitionIterable.

Collect pattern

Transform a collection’s elements, creating a new collection: includes collect, flatCollect, and groupBy.

The Collect pattern methods return a new collection whose data elements are the results of an evaluation performed by the code block; that is, each element of the original collection is mapped to a new object, which is usually a different type. The code block used as the collect method’s parameter implements the Function interface.

Eclipse Collections provides two specialized variations on the Collect pattern: the FlatCollect (or Flatten) pattern and the GroupBy pattern. As with Collect, the patterns' methods take a single Function as a parameter.

Example 15. Collect pattern (pseudocode)
create <newCollection>
 for each <element> of <collection>
     <result> = transform(<element>)
     add <result> to <newCollection>
Example 16. Collect using a lambda and using a method reference
MutableList<Address> addresses =
    people.collect(person -> person.getAddress());

//or

MutableList<Address> addresses =
    people.collect(Person::getAddress);
Example 17. Collect using an anonymous inner class
MutableList<Person> people =...;
Function<Person, Address> addressFunction =
    new Function<Person, Address>()
    {
        public Address valueOf(Person person)
        {
            return person.getAddress();
        }
    };
MutableList<Address> addresses = people.collect(addressFunction);

Notice that this assumes each person in the people collection has just one address.

If, instead, a person has multiple addresses, the Function returns a list of addresses for each person (a list that has only one element if the person has just one address). The result is a List of Lists.

Example 18. Collect using a lambda and using a method reference
MutableList<MutableList<Address>> addresses =
    people.collect(person -> person.getAddresses());

//or

MutableList<MutableList<Address>> addresses =
    people.collect(Person::getAddresses);
Example 19. Collect using an anonymous inner class
MutableList<Person> people =...;
Function<Person, MutableList<Address>> addressFunction =
    new Function<Person, MutableList<Address>>()
    {
        public MutableList<Address> valueOf(Person person)
        {
            return person.getAddresses();
        }
    };
MutableList<MutableList<Address>> addresses =
    people.collect(addressFunction);
Example 20. Collect in Java 8+ Streams using Collectors2
MutableList<MutableList<Address>> addresses = people.stream()
    .map(person -> person.getAddresses())
    .collect(Collectors2.toList());

//or

MutableList<MutableList<Address>> addresses = people.stream()
    .collect(Collectors2.collect(Person::getAdddresses, Lists.mutable::empty));
Example 21. Collect pattern in imperative Java
List<Address> addresses = Lists.mutable.empty();
for (Person person : people)
{
    addresses.add(person.getAddress());
}

//or for multiple addresses

List<List<Address>> addresses = Lists.mutable.empty();
for (Person person : people)
{
    addresses.add(person.getAddresses());
}

Collect methods

These Eclipse Collections methods implement the Collect pattern:

collect(Function): RichIterable

For each element of the collection, the Function is evaluated with the current element as the argument; returns a new collection with the transformed type.

collectInt(IntFunction): IntIterable

Similar to collect, but it takes an IntFunction and returns a primitive collection which extends from IntIterable. There are variants for all eight primitives: collectBoolean, collectFloat etc.

collect(Function, targetCollection): targetCollection

Same as collect, except that the results are added to the specified targetCollection, which extends java.util.Collection.

collectInt(IntFunction, targetCollection): targetCollection

Same as collectInt, except that the results are added to the specified targetCollection, which extends MutableIntCollection. There are variants for all eight primitives.

collectIf(Predicate, Function): RichIterable

Same as collect, except that the Predicate is first evaluated with the element as the argument to filter the collection.

collectIf(Predicate, Function, argument2): RichIterable

Same as collect, but the Function2 is evaluated with the element as one argument, plus one additional argument; returns a new collection of the same size and the transformed type.

collectWith(Function2, argument2, targetCollection): targetCollection

Same as collectWith, except that the results are added to a specified targetCollection. (On all RichIterables since version 1.0)

FlatCollect pattern

Create a single, linear collection from selected values of a collection’s elements.

The FlatCollect or Flatten pattern is a specialized form of the the Collect pattern. It returns a single-level, or "flattened," collection of attribute values from a source collection’s elements.

flatCollect(Function): RichIterable

Applies the Function to each element. The Function must return an Iterable type. Returns the intermediate Iterables in a single, flattened collection.

Given a list of people, as in the collect method examples, here is how flatCollect could be used to create a flat list from the address fields of the person objects in that list, using the same Function (addressFunction):

Example 22. Pseudocode
create <newCollection>
 for each <element> of <collection>
     <results> = transform(<element>)
     Add all <results> to <newCollection>
Example 23. FlatCollect using a lambda and using a method reference
MutableList<Address> flatAddress =
    people.flatCollect(person -> person.getAddresses());

// or

MutableList<Address> flatAddress =
    people.flatCollect(Person::getAddresses);

Note the flatCollect method’s similarity to a collect method having the same signature: each method’s Function parameter maps to an Iterable type. This is optional for collect, but required of flatCollect. Both methods return a new collection. The difference is that collect in this form creates a collection of collections from a simple List, Set or Bag, while flatCollect performs a different (and in this instance, somewhat more useful) action, returning a flat list of addresses.

Example 24. FlatCollect using an anonymous inner class
MutableList<Address> addresses =
    people.flatCollect(
       new Function<Person, MutableList<Address>>()
       {
           public MutableList<Address> valueOf(Person person)
           {
               return person.getAddresses();
           }
       });
Example 25. FlatCollect in Java 8+ Streams using Collectors2
MutableList<Address> flatAddress = people.stream()
    .collect(Collectors2.flatCollect(Person::getAddresses, Lists.mutable::empty));
Example 26. FlatCollect in imperative Java
List<Address> addresses = Lists.mutable.empty();
for (Person person : people)
{
    addresses.addAll(person.getAddresses());
}

GroupBy pattern

Create a Multimap from a collection by grouping on a selected or generated key value.

The GroupBy pattern gathers the elements on the collection into a map-like container called a Multimap, which associates multiple values for each key. The Function is applied to each element and the result is used as the key into the Multimap where the element should appear as the value.

See the discussion of Multimap for examples of groupby.

groupBy(Function): Multimap

Group the elements into a new Multimap; uses the Function to get the key for each element.

groupBy(Function, targetMultimap) : targetMultimap

Same as groupBy except that results are added to the specified targetMultimap.

groupByEach(Function): Multimap

Same as groupBy except that the Function transforms each value into multiple keys, returning a new Multimap containing all the key/value pairs.

Short-circuit patterns

Methods that control processing by testing a collection for a logical condition: includes detect, anySatisfy, and allSatisfy.

The "short-circuit" patterns—Detect, AnySatisfy and AllSatisfy—are so called because they describe methods that cease execution when a specific condition is met. With each iteration, the Predicate is evaluated. If the evaluation resolves as a specified boolean (true/false) value, then iteration halts and returns the appropriate value.

Detect pattern

Finds and returns the first element that satisfies a given logical expression.

Detect returns the first element that satisfies a Predicate. If every element in the collection is tested and the Predicate never returns true, then the method returns null.

Example 27. Detect pattern (pseudocode)
for each <element> of <collection>
  if condition(<element>)
    return <element> // and end process
Example 28. Detect using a lambda
Integer result =
    list.detect(each -> each > 50);
Example 29. Detect using a Predicates factory
Integer result =
    list.detect(Predicates.greaterThan(50));
Example 30. Detect in Java 8+ Streams
Integer result =
    list.stream().findAny(each -> each > 50).get();
Example 31. Detect in imperative Java
for (int i = 0; i < list.size(); i++)
{
    Integer v = list.get(i);
    if (v.intValue() > 50)
    {
        return v;
    }
}
return null;

Detect methods

detect(Predicate): element

Returns the first element which satisfies the Predicate or null if no element satisfies the Predicate.

detectIfNone(Predicate, Function0): element (or Function0 result)

Same as detect, but if no element causes Predicate to evaluate as true, return the result of evaluating Function0.

detectWith(Predicate2, parameter): element

Returns the first element that evaluates as true for the specified Predicate2 and parameter, or null if none evaluate as true. See Reusing a code block for more information.

detectWithIfNone(Predicate2, parameter, Function0): element (or Function0 result)

Same as detectWith, but if no element causes Predicate2 to evaluate as true, return the result of evaluating Function0.

AnySatisfy pattern

Determine if any collection element satisfies a given logical expression.

The AnySatisfy pattern determines whether any element of a collection satisfies a Predicate. It applies the Predicate to each element; if the Predicate returns true, execution halts and the method returns true immediately. Otherwise, every element is checked and the method returns false.

Example 32. AnySatisfy (pseudocode)
for each <element> of <collection>
     if condition(<element>)
         return true  // and end process
 otherwise return false
Example 33. AnySatisfy using a lambda
boolean result =
    list.anySatisfy(num -> num > 50);
Example 34. AnySatisfy using a Predicates factory
boolean result =
    list.anySatisfy(Predicates.greaterThan(50));
Example 35. AnySatisfy in Java 8+ Streams
boolean result =
    list.stream().anyMatch(num -> num > 50);
Example 36. AnySatisfy in imperative Java
for (int i = 0; i < list.size(); i++)
{
    Integer v = list.get(i);
    if (v.intValue() > 50)
    {
        return true;
    }
}
return false;

AnySatisfy methods

anySatisfy(Predicate): boolean

Returns true if the Predicate returns true for any element of the collection. Otherwise (or if the collection is empty), return false.

anySatisfyWith(Predicate2, parameter): boolean

Returns true if the Predicate2 returns true for any element of the collection. Otherwise (or if the collection is empty), return false.

AllSatisfy pattern

Determine if all collection elements satisfy a given logical expression.

The AllSatisfy pattern is the inverse of AnySatisfy. It reports whether all elements satisfy a Predicate. It applies the Predicate to each element; if the Predicate returns false, execution halts and the method returns false immediately. Otherwise, every element is checked and the method returns true.

Example 37. AllSatisfy (pseudocode)
for each <element> of <collection>
     if not condition(<element>)
         return false  // and end process
 otherwise return true
Example 38. AllSatisfy using a lambda
boolean result =
    list.allSatisfy(each -> each > 50);
Example 39. AllSatisfy using a Predicates factory
boolean result =
    list.allSatisfy(Predicates.greaterThan(50));
Example 40. AllSatisfy in Java 8+ Streams
boolean result =
    list.stream().allMatch(each -> each > 50);
Example 41. AllSatisfy in imperative Java
for (int i = 0; i < list.size(); i++)
{
    Integer v = list.get(i);
    if (v.intValue() <= 50)
    {
        return false;
    }
}
return true;

NoneSatisfy is similar to AllSatisfy, but negates the Predicate. It returns true only if no element satisfies the Predicate. If the container is empty it also returns true.

AllSatisfy methods

allSatisfy(Predicate): boolean

Returns true if the Predicate returns true for all elements of the collection. Otherwise (or if the collection is empty), return false.

allSatisfyWith(Predicate2, parameter): boolean

Return true if the Predicate2 returns true for all elements of the collection. Otherwise (or if the collection is empty), return false.

noneSatisfy(Predicate):* boolean*

Return true if the Predicate returns false for all elements of the collection or if the collection is empty. Otherwise, return false.

noneSatisfyWith(Predicate2, parameter): boolean

Return true if the Predicate2 returns false for all elements of the collection or if the collection is empty. Otherwise, return false.

ForEach pattern

Perform a calculation on each element of the current collection.

The ForEach pattern defines the most basic iteration operation that can be used with all collection types. Unlike the other patterns discussed in this topic, the ForEach pattern prescribes methods that operate on each element of the calling collection object, with no value returned by the method itself.

In Eclipse Collections, the each and forEach methods offer the most straightforward replacement for the Java for loop. It executes the code in a Procedure on each element. You can use these methods to perform some action using the values of the source collection—for example, to print a value or to call another method on each element.

Example 42. ForEach (pseudocode)
for each <element> of <collection>
     evaluate(<element>)
Example 43. ForEach using a lambda
list.each(each -> doSomething(each));

// or

list.forEach(each -> doSomething(each));
Example 44. ForEach using an anonymous inner class
list.each(new Procedure()
{
    public void value(Object each)
    {
        doSomething(each);
    }
});
Example 45. ForEach in imperative Java
for (int i = 0; i < list.size(); i++)
{
    this.doSomething(list.get(i));
}

Each and ForEach methods

each(Procedure): void

For each element, the Procedure is evaluated with the element as the argument.

forEach(Procedure): void

For each element, the Procedure is evaluated with the element as the argument.

forEachIf(Predicate, Procedure): void

For each element that satisfies the Predicate, executes the Procedure on that element.

forEach(fromIndex, toindex, Procedure): void

Iterates over the section of a ListIterable covered by the specified indexes (inclusive).

forEachWith(Procedure2, parameter): void

For each element of the collection, the Procedure2 is evaluated with the element as the first argument, and the specified parameter as the second argument.

forEachWithIndex(ObjectIntProcedure): void

Iterates over a collection passing each element and the current relative int index to the specified instance of ObjectIntProcedure.

forEachWithIndex(fromIndex, toIndex, ObjectIntProcedure): void

Iterates over the section of the list covered by the specified indexes (inclusive).

InjectInto pattern

Calculate and maintain a running value during iteration; use each evaluated result as an argument in the next iteration.

The InjectInto pattern is used to carry a computed result from one iteration as input to the next. In this pattern, the injectInto method takes an initial injected value as a parameter. This value is used as the first argument to a two-argument code block; the current element (for each iteration of the collection) is taken as the second argument.

For each iteration, the code block’s evaluation result is passed to the next iteration as the first argument (the injected value) of the code block, with the (new) current element as the second argument. The injectInto() method returns the code block’s cumulative result upon the final iteration.

Example 46. InjectInto (pseudocode)
set <result> to <initialvalue>
 for each <element> of <collection>
     <result> = apply(<result>, <element>)
 return <result>
Example 47. InjectInto using a lambda and using a method reference
Integer result =
    Lists.mutable.of(1, 2).injectInto(3, (result, each) -> result + each);

// or

Integer result =
    Lists.mutable.of(1, 2).injectInto(3, Integer::sum);
Example 48. InjectInto using a static class
Integer result =
    Lists.mutable.of(1, 2).injectInto(3, AddFunction.INTEGER);
Example 49. InjectInto in Java 8 Streams using a lambda and using a method reference)
Integer result =
    Lists.mutable.of(1, 2).stream().reduce(3, (result, each) -> result + each);

// or

Integer result =
    Lists.mutable.of(1, 2).stream().reduce(3, Integer::sum);
Example 50. InjectInto in imperative Java
List<Integer> list = Lists.mutable.of(1, 2);
int result = 3;
for (int i = 0; i < list.size(); i++)
{
    Integer v = list.get(i);
    result = result + v.intValue();
}

InjectInto methods

injectInto(injectedValue, Function2): (final result)

Return the final result of all evaluations using as the arguments each element of the collection, and the result of the previous iteration’s evaluation.

injectInto(floatValue, FloatObjectToFloatFunction): float

Return the final result of all evaluations using as the arguments each element of the collection, and the result of the previous iteration’s evaluation. The injected value and result are both primitive floats.

injectInto(intValue, IntObjectToIntFunction): int

Return the final result of all evaluations using as the arguments each element of the collection, and the result of the previous iteration’s evaluation. The injected value and final result are both primitive ints.

injectInto(longValue, LongObjectToLongFunction): long

Return the final result of all evaluations using as the arguments each element of the collection, and the result of the previous iteration’s evaluation. The injected value and result are both primitive longs.

injectInto(doubleValue, DoubleObjectToDoubleFunction): double

Return the final result of all evaluations using as the arguments each element of the collection, and the result of the previous iteration’s evaluation. The injected value and result are both primitive doubles.

RichIterable

The superinterface that specifies the iteration patterns in Eclipse Collections container types.

RichIterable is the most important interface in Eclipse Collections. It provides the blueprint for all non-mutating iteration patterns. It represents an object made up of elements that can be individually and consecutively viewed or evaluated (an iterable), and it prescribes the actions that can be performed with each evaluation (the iteration patterns). The most commonly used implementations include FastList and UnifiedSet.

RichIterable is extended by ListIterable, SetIterable, Bag, StackIterable, and MapIterable. A MapIterable of keys and values is also a RichIterable of values. (Note that Multimap and its subinterfaces have a separate API.)

RichIterable is also extended by MutableCollection, and indirectly by MutableList and MutableSet (which also extend the mutable Java Collection types List and Set). Another subinterface defines a non-JDK container, MutableBag (or multiset); yet another, ImmutableCollection, delineates the immutable forms of these Eclipse Collections containers. These latter two interfaces are detailed in the Collections and containers topic.

The subinterface LazyIterable for the most part replicates RichIterable, but overrides some specific collection-returning methods— collect, collectIf, select, reject, and flatCollect—so that they delay their actual execution until the returned collection is needed, a technique called "lazy iteration."

Lazy iteration

Deferring evaluation until necessary.

Lazy iteration is an optimization pattern in which an iteration method is invoked, but its actual execution is deferred until its action or return values are required by another, subsequent method. In practical terms, the objective is typically to forestall unnecessary processing, memory use, and temporary-object creation unless and until they are needed.

Lazy iteration is implemented as an adapter on the current RichIterable collection by the asLazy method:

richIterable.asLazy()

Returns a deferred-evaluation iterable of type LazyIterable. (Note the list below of other Eclipse Collections methods that return lazy Iterables.)

In a way, lazy iteration is a companion to the short-circuit iteration patterns, in which iteration ceases as soon the method’s purpose is achieved. In the last line of the example below, the anySatisfy method quits execution when it detects the "address2" element in the addresses list created by collect. The third element ("address 3") is never examined by anySatisfy - although it was present in addresses.

Example 51. anySatisfy and collect using an anonymous inner class
Person person1 = new Person(address1);
Person person2 = new Person(address2);
Person person3 = new Person(address3);
MutableList<Person> people =
    Lists.mutable.with(person1, person2, person3);
MutableList<MutableList<Address>> addresses =
    people.collect(addressFunction);
Assert.assertTrue(addresses.anySatisfy(Predicates.equal(address2)));

One excess element out of three may be trivial, but if people were to be a very long list (or a stream), anySatisfy will still have to wait for the collect method to finish aggregating an equally-large temporary collection - one that will have only its first two elements inspected. By applying a lazy-iteration adapter to people, the collect iteration defers to that of anySatisfy: only the elements anySatisfy requires are "collected."

Example 52. anySatisfy and collect using a Predicates factory)
MutableList<Person> people = Lists.mutable.with(person1, person2, person3);
LazyIterable<Person> lazyPeople = people.asLazy();
LazyIterable<Address> addresses = lazyPeople.collect(addressFunction);
Assert.assertTrue(addresses.anySatisfy(Predicates.equal(address2)));

This example demonstrates lazy iteration using both Java 8 lambdas and method references:

Example 53. Lazy iteration using a lambda and using a method reference
LazyIterable<Person> lazyPeople = people.asLazy();
LazyIterable<Address> addresses =
    lazyPeople.flatCollect(person -> person.getAddresses());

//or

LazyIterable<Address> addresses =
    lazyPeople.flatCollect(Person::getAddresses);

Finally, note these Eclipse Collections methods that implicitly return a lazy-iterable type.

Lazy interables in MutableMap implementations

valuesView() : RichIterable

An unmodifiable view of the map’s values.

keysView() : RichIterable

An unmodifiable view of the map’s keyset.

keyValuesView() : RichIterable

An unmodifiable view of the map’s entryset.

Lazy interables in Multimap implementations

keyMultiValuePairsView() : RichIterable

An unmodifiable view of key and multi-value pairs.

keysView() : RichIterable

An unmodifiable view of unique keys.

keyValuePairsView() : RichIterable

An unmodifiable view of key/value pairs.

multiValuesView() : RichIterable

An unmodifiable view of each key’s values, without the key.

Parallel-lazy iteration

An API that combines parallel iteration with lazy evaluation.

Parallel-eager utility is available through the ParallelIterate utility class. Serial-lazy evaluation is available through LazyIterable, the view returned by RichIterable.asLazy(). The ParallelIterable interface defines a view where iteration is both parallel and lazy. Sub-interfaces of ParallelIterable are returned from the various implementations of asParallel( ExecutorService executorService, int batchSize ). The ParallelIterable API is new in 5.0 and considered experimental, as indicated by the @Beta annotation. API tagged as @Beta may be altered in ways that are not backward-compatible, even in minor versions of Eclipse Collections. The method asParallel is not on interfaces like RichIterable in version 5.0, but rather on a few supported collections, including FastList and UnifiedSet.

FastList integers = Lists.mutable.with(1, 2, 3, 4, 5, 6, 7, 8, 9);
ExecutorService threadPool =
  Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
int batchSize = 2;
ParallelListIterable parallelListIterable =
  integers.asParallel(threadPool, batchSize);
// deferred evaluation
ParallelListIterable evenNumbers =
  parallelListIterable.select(each -> each % 2 == 0);
// deferred evaluation
ParallelListIterable evenStrings =
  evenNumbers.collect(Object::toString);
// forced evaluation
MutableList strings = evenStrings.toList();
threadPool.shutdown();
Assert.assertEquals(Lists.mutable.with("2", "4", "6", "8"), strings);

In this code example, the calls to select and collect are lazy, as indicated by the fact that they return subclasses of ParallelIterable. The call to toList() forces evaluation.

The two parameters to asParallel(ExecutorService executorService, int batchSize) are used to configure parallelism.

executorService

This code example sets up a thread pool with one thread per core, which is appropriate for CPU-bound tasks. A thread pool used for I/O bound tasks should be infinite or should have one thread per I/O-bound resource, for example, one thread per database connection. It often makes sense to share thread pools between multiple calls to asParallel.

batchSize

The batch size determines the number of elements from the backing collection (FastList or UnifiedSet) that get processed by each task submitted to the thread pool. Appropriate batch sizes for CPU-bound tasks are usually larger, in the 10,000 to 100,000 range.

Performance

As with lazy evaluation, there is no guarantee that using parallel-lazy evaluation will yield better performance than simple serial-eager evaluation. Performance testing is required, using an appropriate thread pool and trying various batch sizes.

Cancelability

It’s possible to cancel a parallel-lazy computation in progress. It requires a thread pool that can be shut down, which means it usually won’t be a thread pool shared between multiple computations. Cancelling also requires a runnable thread with access to the thread pool. Building on the previous example, we just need to change evenStrings.toList() to execute in a background thread. Then the main thread could call threadPool.shutdownNow() which would cause toList() to terminate relatively quickly by throwing an exception. Shutting down the thread pool won’t stop any batches in progress. However, no new batches will be started.

RichIterable methods

These methods are available on all implementations of RichIterable.

Building strings

Methods that convert collection elements to a string that can be appended to a stream or buffer.

The makeString method returns a representation of the calling RichIterable collection as a String object. Elements are converted to strings as they would be by String.valueOf(Object). You can specify start and end strings as delimiters (the default is an empty string for both) and the separator string for the between-values delimiter (defaults to comma and space).

makeString(startString, separatorString, endString): String

Returns a string representation of the calling collection that is a list of elements in the order they are returned by the iterator, enclosed in the startString and endString. Elements are delimited by the separatorString.

makeString(separatorString): String

Same result with no starting and ending strings.

makeString(): String

Same result with the default delimiter ", " (comma space) and no starting and ending strings.

Example 54. makeString
MutableList<Integer> list = Lists.mutable.with(1, 2, 3);
String myDelim = list.makeString("[", "/", "]"); // "[1/2/3]"
String mySeper = list.makeString("/"); // "1/2/3"
String defaultString = list.makeString(); //"1, 2, 3"
Example 55. Building strings in Java 8+ Streams
MutableList<Integer> list = Lists.mutable.with(1, 2, 3);
String myDelim =
    list.stream().map(Object::toString).collect(Collectors.joining("/", "[", "]")); // "[1/2/3]"
String mySeper =
    list.stream().map(Object::toString).collect(Collectors.joining("/")); // "1/2/3"
String defaultString =
    list.stream().map(Object::toString).collect(Collectors.joining()); // "1/2/3"
Example 56. Building strings in Java 8+ Streams with Collectors2
MutableList<Integer> list = Lists.mutable.with(1, 2, 3);
String myDelim =
    list.stream().collect(Collectors2.makeString("[", "/", "]")); // "[1/2/3]"
String mySeper =
    list.stream().collect(Collectors2.makeString("/")); // "1/2/3"
String defaultString =
    list.stream().collect(Collectors2.makeString()); // "1/2/3"

The appendString method uses forms similar to makeString, but the string representation of the collection is written to a Java Appendable object, such as a PrintStream, StringBuilder or StringBuffer; the method itself is void.

appendString(Appendable, startString, separatorString, endString): void

Appends a string representation of this collection onto the given Appendable using the specified start, end, and separator strings

appendString(Appendable, separatorString): void

Appends with specified separator, but no starting or ending strings.

appendString(Appendable): void

Appends with the default delimiter ", " (comma space) and no starting and ending strings.

Example 57. appendString
MutableList<Integer> list = Lists.mutable.with(1, 2, 3);
Appendable myStringBuilder = new StringBuilder();
list.appendString(myStringBuilder, "[", "/", "]"); //"[1/2/3]");

Counting elements

Get the total number of elements that satisfy a condition.

The count and countWith methods calculate the number of collection elements that satisfy a given predicate. The countWith method takes a second parameter that is used as an additional argument in evaluating the current element.

count(Predicate): int

Returns the number of elements that satisfy the Predicate. For example:

Here is a Java 8+ lambda example:

Example 58. count using a lambda
int count =
    people.count(person -> person.getAddress().getState().getName().equals("New York"));
Example 59. count using an anonymous inner class
int count =
    people.count(new Predicate<Person>()
    {
      public boolean value(Person person)
      {
        return person.getAddress().getState().getName().equals("New York");
      }
    });

countWith(Predicate2, parameter): int

Returns the number of elements that satisfy the Predicate2. The second parameter to countWith is passed as the second parameter to the Predicate2.

Example 60. count using a Predicates2 factory
int count =
    lastNames.countWith(Predicates2.equal(), "Smith");

Use these methods to get the total number of collection items or to determine whether the collection is empty.

size() : int

Returns the number of items in the collection.

isEmpty() : boolean

Returns true if this iterable has zero items.

notEmpty() : boolean

Returns true if this iterable has greater than zero items.

Finding elements

Locate elements by iteration position or highest/lowest value.

The getFirst and getLast methods return the first and last elements, respectively of a RichIterable collection. In the case of a List, these are the elements at the first and last index. For all any other collections, getFirst and getLast return the first and last elements that would be returned by an iterator. Note that the first or last element of a hash-based Set could be any element, because element order in a hashed structure is not defined. Both methods return null if the collection is empty. If null is a valid element, use the isEmpty method to determine if the container is in fact empty.

getFirst(): element

Returns the first element of an iterable collection.

getLast(): element

Returns the last element of an iterable collection.

The min and max methods, without parameters, return an element from an iterable based on its natural order, that is, by calling the compareTo() method on each element.

max(): element

Returns the maximum value based on the natural ordering.

min(): element

Returns the minimum value based on the natural ordering.

Example 61. max and min
RichIterable<Integer> iterable = Lists.mutable.with(5, 4, 8, 9, 1);
Assert.assertEquals(Integer.valueOf(9), iterable.max());
Assert.assertEquals(Integer.valueOf(1), iterable.min());

If any element in the iterable is not Comparable, then a ClassCastException is thrown.

RichIterable<Object> iterable = Lists.mutable.with(5, 4, 8, 9, 1, new Foo());
iterable.max(); // throws ClassCastException

The min and max methods each have an overload that takes a Comparator that determines the natural order.

max(Comparator): element

Returns the maximum element out of this collection based on the comparator.

min(Comparator): element

Returns the minimum element out of this collection based on the comparator.

Example 62. max and min
public class SillyWalk
{
  public final int wiggles;

  public SillyWalk(int wiggles)
  {
    this.wiggles = wiggles;
  }
}
private static final Comparator<SillyWalk> SILLY_WALK_COMPARATOR =
    new Comparator<SillyWalk>()
    {
      public int compare(SillyWalk o1, SillyWalk o2)
      {
        return o1.wiggles - o2.wiggles;
      }
    };
SillyWalk sillyWalk2 = new SillyWalk(2);
SillyWalk sillyWalk3 = new SillyWalk(3);
RichIterable<SillyWalk> walks = Lists.mutable.with(sillyWalk2, sillyWalk3);
Assert.assertEquals(sillyWalk3,walks.max(SILLY_WALK_COMPARATOR));
Assert.assertEquals(sillyWalk2,walks.min(SILLY_WALK_COMPARATOR));

The related methods minBy and maxBy take a Function and return the minimum or maximum element in the RichIterable based on the natural order of the attribute returned by the Function.

maxBy(Function): element

Returns the maximum element out of this collection based on the result of applying the Function to each element.

minBy(Function): element

Returns the minimum element out of this collection based on the result of applying the Function to each element.

Here, we find the youngest person (the minimum person by age).

Example 63. minBy using a method reference
Person alice = new Person("Alice", 40);
Person bob = new Person("Bob", 30);
Person charlie = new Person("Charlie", 50);
MutableList<Person> people = Lists.mutable.with(alice, bob, charlie);
Assert.assertEquals(bob, people.minBy(Person::getAge));

In this code example we already had a Function, so calling minBy was more concise than calling min(). These two forms are equivalent though.

people.minBy(Person::getAge);
people.min(Comparators.byFunction(Person::getAge));

Aggregating elements

Methods that create maps of aggregated values by grouping them on a calculated key.

The aggregateBy method groups elements in the RichIterable by the Function. Then all the elements that map to the same key are aggregated together using the Function2. The third parameter, a Function0, creates the initial value in each aggregation. Aggregate results are allowed to be immutable as they will be replaced in the map.

aggregateBy is conceptually analogous to calling a groupBy method on a RichIterable to create a Multimap, and then calling injectInto on each collection of the Multimap values to create a MapIterable.

aggregateInPlaceBy is similar to aggregateBy, but it mutates values in the output map instead of replacing them. Thus in this case, the aggregate results must be mutable.

aggregateBy(Function, Function0, Function2): MapIterable

Returns a MapIterable by grouping results by keys supplied by evaluating a Function.

Example 64. aggregateBy using a lambda and a method reference
FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);
MutableMap<Integer, Integer> aggregation =
integers.aggregateBy(
        integer -> integer % 2,
        () -> 0,
        Integer::sum);
Assert.assertEquals(4, aggregation.get(0).intValue());
Assert.assertEquals(6, aggregation.get(1).intValue());
Example 65. aggregateBy using anonymous inner classes
Function0<Integer> factory = new Function0<Integer>()
{
    public Integer value()
    {
        return Integer.valueOf(0);
    }
};
Function2<Integer, Integer, Integer> sumAggregator =
new Function2<Integer,
        Integer, Integer>()
{
    public Integer value(Integer aggregate, Integer value)
    {
        return aggregate + value;
    }
};
Function<Integer, Integer> groupBy =
new Function<Integer, Integer>()
{
    public Integer valueOf(Integer integer)
    {
        return integer % 2;
    }
};
FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);
MutableMap<Integer, Integer> aggregation = integers.aggregateBy(groupBy, factory, sumAggregator);
Assert.assertEquals(4, aggregation.get(0).intValue());
Assert.assertEquals(6, aggregation.get(1).intValue());

aggregateInPlaceBy(Function, Function0, Function2): MapIterable

Returns the same result as aggregateBy with no starting and ending strings.

Example 66. aggregateInPlaceBy using a lambda and a method reference
FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);
MutableMap<Integer, AtomicInteger> aggregation =
integers.aggregateInPlaceBy(
        integer -> integer % 2,
        () -> new AtomicInteger(0),
        AtomicInteger::addAndGet)
Assert.assertEquals(4, aggregation.get(0).intValue());
Assert.assertEquals(6, aggregation.get(1).intValue());
Example 67. aggregateInPlaceBy using anonymous inner classes
Function0<AtomicInteger> factory = new Function0<AtomicInteger>()
{
    public AtomicInteger value()
    {
        return new AtomicInteger(0);
    }
};
Procedure2<AtomicInteger, Integer> sumAggregator = new Procedure2<AtomicInteger, Integer>()
{
    public void value(AtomicInteger aggregate, Integer value)
    {
        aggregate.addAndGet(value);
    }
};
Function<Integer, Integer> groupBy =
new Function<Integer, Integer>()
{
    public Integer valueOf(Integer integer)
    {
        return integer % 2;
    }
};
FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);
MutableMap<Integer, AtomicInteger> aggregation = integers.aggregateInPlaceBy(groupBy, factory, sumAggregator);
Assert.assertEquals(4, aggregation.get(0).intValue());
Assert.assertEquals(6, aggregation.get(1).intValue());

Creating collections using chunk and zip

Grouping and pairing elements of one or more collections.

The chunk method can be used to gather the elements of a collection into chunks; that is, it creates a collection made up of collections of a specified fixed size (an integer). If the size doesn’t divide evenly into the total of collection elements, then the final chunk is smaller.

chunk(size): RichIterable

Returns a new collection with the source collection’s elements grouped in "chunks," with size elements in each chunk, and the last chunk containing the remaining elements, if any.

Example 68. chunk
MutableList<Integer> list =
    Lists.mutable.with(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
RichIterable<RichIterable<Integer>> chunks = list.chunk(4);
System.out.println(chunks);

This example prints out:

[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]

The zip method pairs up the elements of one RichIterable with those of second. If one of the two collections has more elements than the other, those remaining elements are dropped. The zipWithIndex method is a special case of zip that pairs the elements in a collection with their index positions.

zip(RichIterable): RichIterable

Returns a new RichIterable by combining, into pairs, corresponding elements from the calling RichIterable collection and the RichIterable collection named in the parameter. If one of the two collections is longer, its remaining elements are ignored..

Example 69. zip
MutableList<String> list1 = Lists.mutable.with("One", "Two", "Three", "Truncated");
MutableList<String> list2 = Lists.mutable.with("Four", "Five", "Six");
MutableList<Pair<String, String>> pairs = list1.zip(list2);
System.out.println(pairs);

This example prints out:

[One:Four, Two:Five, Three:Six]

zipWithIndex(): RichIterable

Returns a new RichIterable consisting of the calling collection’s elements, each paired with its index (beginning with index 0).

Example 70. zipWithIndex
MutableList<String> list = Lists.mutable.with("One", "Two", "Three");
MutableList<Pair<String, Integer>> pairs = list.zipWithIndex();
System.out.println(pairs);

This example prints out:

[One:0, Two:1, Three:2]

Reusing code blocks

Using selectWith, rejectWith, and collectWith inside other iteration patterns (or loops) where code blocks can be created outside of the outer iteration patterns or made static.

The collection-returning iteration methods - collect, select, and reject - each take a single parameter: a code block that itself takes a single argument. These patterns have alternate forms, methods named collectWith, selectWith, andrejectWith respectively. The same is true of the boolean-returning short-circuit methods, detect, anySatisfy, allSatisfy, and noneSatisfy; each has a counterpart having the suffix "With." All of these are available on RichIterable and its subinterfaces.

In each case, the "…​With" form of the method takes two parameters:

  • The first method parameter is a code block that itself takes two arguments; the first argument of the code block is the current element with each iteration.

  • The second method parameter is an object that is then passed to the code block as its second argument.

selectWith(Predicate2, argument): RichIterable

rejectWith(Predicate2, argument): RichIterable

For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additional argument; selected or rejected elements are returned in a new collection of the same type.

collectWith(Predicate2, argument): RichIterable

Same as the collect method, but two arguments are passed to the code block; returns a new collection of the same type and size.

Note

These " …​With" forms accomplish exactly the same actions as their basic counterparts. Although slightly more verbose, they allow for a specific performance optimization, that is, the reuse of the code block with different arguments.

Here is an example of select that finds the adults in a list of people. First, the JDK version, and then rewritten in Eclipse Collections form:

Example 71. Select pattern in imperative Java
List<Person> people =...;
List<Person> adults = Lists.mutable.empty();
for (Person person : people)
{
  if (person.getAge() >= 18)
  {
    adults.add(person);
  }
}
Example 72. Select in Eclipse Collections using a lambda
MutableList<Person> people =...;
MutableList<Person> adults =
    people.select(each -> each.getAge() >= 18);
Example 73. Select in Eclipse Collections using an anonymous inner class)
MutableList<Person> people =...;
MutableList<Person> adults = people.select(
    new Predicate<Person>()
    {
      public boolean accept(Person each)
      {
        return each.getAge() >= 18;
      }
    });

Here’s the same algorithm, again in Eclipse Collections, this time using selectWith:

Example 74. selectWith using a lambda and using a method reference
MutableList<Person> people =...;
MutableList<Person> adults =
    people.selectWith((eachPerson, age) -> eachPerson.getAge() > age, 18);

// or

MutableList<Person> adults =
    people.selectWith(Person::isOlderThan, 18);
Example 75. selectWith using an anonymous inner class
MutableList<Person> people =...;
MutableList<Person> adults = people.selectWith(
    new Predicate2<Person, Integer>()
    {
      @Override
      public boolean accept(Person eachPerson, Integer age)
      {
        return eachPerson.getAge() > age;
      }
    }, 18);

In this single instance, there is no reason to write it out this longer way; the extra generality - making age the second argument to the Predicate2 - is unnecessary.

It does make sense, however, if you wanted to filter on multiple ages: you could hold onto and reuse the Predicate2, thereby creating less garbage.

Example 76. EC selectWith using an anonymous inner class
MutableList<Person> people =...;
Predicate2<Person, Integer> agePredicate =
    new Predicate2<Person, Integer>()
    {
      @Override
      public boolean accept(Person eachPerson, Integer age)
      {
        return eachPerson.getAge() > age;
      }
    };
MutableList<Person> drivers = people.selectWith(agePredicate, 17);
MutableList<Person> voters = people.selectWith(agePredicate, 18);
MutableList<Person> drinkers = people.selectWith(agePredicate, 21);

collectWith, selectWith, and rejectWith work well with method references.

Example 77. selectWith using a method reference
MutableList<Person> drivers = people.selectWith(Person::isOlderThan, 17);
MutableList<Person> voters = people.selectWith(Person::isOlderThan, 18);
MutableList<Person> drinkers = people.selectWith(Person::isOlderThan, 21);

This style encourages adding more behavior to the classes held in the containers. This style works with any "…​With" method in Java 8 or higher.

Map iteration methods

Methods for iterating over Maps and Multimaps.

The MapIterable and Multimap interfaces are associative arrays that contain key-value pairs. All of the keys in a MapIterable are unique; a Multimap can have multiple values associated with each key.

The Multimap interface does not extend MapIterable. Multimap has a number of subinterfaces, such as ListMultimap, SetMultimap, and BagMultimap, each with custom behavior for how to handle the collection of values associated with each key.

Creating iterable views of maps

Wrapper classes that return an iterable view of a map; ForEach patterns for Map containers.

These three methods each return an unmodifiable RichIterable view of a Map. They are essentially wrappers over the modifiable, non-lazy objects returned by the corresponding Java Collections Framework methods.

valuesView(): RichIterable

(Maps and Multimaps) Returns an unmodifiable RichIterable wrapper over the values of the Map.

keysView(): RichIterable

(Maps and Multimaps) Returns an unmodifiable RichIterable wrapper over the keySet of the Map.

keyValuesView(): RichIterable

(Maps only) Returns an unmodifiable lazy iterable of key/value pairs.

ForEach Iteration

These three methods call a code block for each element on a Map; all return void.

forEachKey(Procedure): void

Calls the Procedure on each key of the Map.

forEachValue(Procedure): void

Calls the Procedure on each value of the Map.

forEachKeyValue(Procedure2): void

Calls the Procedure2 on each key-value pair of the Map.

Collecting entries

Gather entries from another collection into a Map.

Use the collectKeysAndValues method to add all the entries derived from another collection into the current Map.

collectKeysAndValues(collection, keyFunction, valueFunction): MutableMap

(Mutable maps only) The key and value for each entry is determined by applying the keyFunction and valueFunction (in each case, a {Function}) to each item in collection. Each is converted into a key-value entry and inserted into the Map. If a new entry has the same key as an existing entry in the calling map, the new entry’s value replaces that of the existing entry.

Finding, testing and putting values

Detect a value by its key and, optionally, insert or return other values.

The updateValue, getIfAbsent and ifPresentApply methods locate a specified key and return a map value that corresponds to that key. Depending on whether a value is found at the given key, each method performs a specific action.

add(Pair<K, V>): value

Adds the given key-value pair to the map. This is a convenience method for working with Pairs, similar to put(K, V).

updateValue(key, Function0, Function): value

If a value in the Map corresponds to the specified key, this method applies the specified Function to the value and replaces the value; otherwise applies the Function to the value supplied by the Function0 and puts the result as a value in the map at the specified key.

updateValueWith(key, Function0, Function2, parameter): value

If a value in the Map corresponds to the specified key, this method applies the specified Function2 to the value and the specified parameter and replaces the value with the result; otherwise applies the Function2 to the value supplied by the Function0 and the parameter and puts the result as a value in the map at the specified key.

getIfAbsent(key, Function0): element (or Function0 result)

Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function0 (here, specifically, a code block without parameters that returns some object).

getIfAbsentPut(key, value): element

Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns specified value, and puts that value in the map at the specified key.

getIfAbsentPut(key, Function0): element (or Function0 result)

Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function0, and puts that value in the map at the specified key

getIfAbsentPutWith(key, Function,parameter): element (or Function result)

Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified one-argument Function using the specified parameter, and put that value in the map at the specified key.

*getIfAbsentWith(key, Function, parameter) : element (or Function result)*

Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function and parameter.

*ifPresentApply(key, Function) : (Function result)*

If there is a value in the Map that corresponds to the specified key, returns the result of evaluating the specified Function with the value, otherwise returns null.

Flipping maps

Return a new associative array where the position of the keys and values have been flipped

flip(): Multimap

Since the values in the MapIterable are not necessarily unique, flip() returns a Multimap instead of a MapIterable.

flipUniqueValues(): MapIterable

Similar to MapIterable.flip() but asserts that the values in the MapIterable are unique and thus returns MapIterable instead of Multimap. Throws IllegalArgumentException if the MapIterable contains duplicate values.

previous: Introduction

next: Collections and containers