EC by Example: Collect

Learn how to transform a collection using the collect method in Eclipse Collections.

The Golden Gate Bridge from Fort Point

What is Collect?

The method named collect in Eclipse Collections takes a Function as a parameter, applies that function to each element in a collection, and returns a the resulting collection. This method is the equivalent of the method named map on the java.util.Stream class in the JDK.

Calling collect on a List with a Function

The method collect in Eclipse Collections derives its name from the Smalltalk method named collect. The method collect will return the same collection type as the source collection (where feasible), but the value type contained in the collection may be different. The method collect in Eclipse Collections should not be confused with the method collect on java.util.Stream which takes a Collector. The method collect on Stream is a more general mutable reduction which may return any type. The method collect on java.util.Stream does not appear on java.util.Collection or any of its extensions. So while there is a conceptual naming collision, there is no overloading of the methods to cause extra confusion.

Collecting from a List (Java 8)

@Test
public void collectingFromAListJava8()
{
ExecutorService executor = Executors.newWorkStealingPool();

MutableList<Integer> mList = mList(1, 2, 3, 4, 5);
ImmutableList<Integer> iList = iList(1, 2, 3, 4, 5);

Function<Integer, Integer> squared = i -> i * i;

MutableList<Integer> mutable = mList.collect(squared);

ImmutableList<Integer> immutable = iList.collect(squared);

LazyIterable<Integer> lazy = mList.asLazy().collect(squared);

ParallelListIterable<Integer> parallel =
mList.asParallel(executor, 2).collect(squared);

ImmutableList<Integer> expected = iList(1, 4, 9, 16, 25);

Assert.assertEquals(expected, mutable);
Assert.assertEquals(expected, immutable);
Assert.assertEquals(expected, lazy.toList());
Assert.assertEquals(expected, parallel.toList());
}

Collecting from a List (Java 10)

@Test
public void collectingFromAListJava10()
{
var executor = Executors.newWorkStealingPool();

var mutableList = mList(1, 2, 3, 4, 5);
var immutableList = iList(1, 2, 3, 4, 5);

Function<Integer, Integer> squared = i -> i * i;

var mutable = mutableList.collect(squared);

var immutable = immutableList.collect(squared);

var lazy = mutableList.asLazy().collect(squared);

var parallel =
mutableList.asParallel(executor, 2).collect(squared);

var expected = iList(1, 4, 9, 16, 25);

Assert.assertEquals(expected, mutable);
Assert.assertEquals(expected, immutable);
Assert.assertEquals(expected, lazy.toList());
Assert.assertEquals(expected, parallel.toList());
}

Notice that Function cannot be replaced with var. This is because a lambda must be assigned to some type.

Collecting from a primitive List (Java 8)

@Test
public void collectingFromAPrimitiveListJava8()
{
MutableIntList mList = IntLists.mutable.with(1, 2, 3, 4, 5);
ImmutableIntList iList = IntLists.immutable.with(1, 2, 3, 4, 5);

IntToIntFunction squared = i -> i * i;

MutableIntList mutable =
mList.collectInt(squared, new IntArrayList());

ImmutableIntList immutable =
iList.collectInt(squared, new IntArrayList())
.toImmutable();

LazyIntIterable lazy =
mList.asLazy().collectInt(squared);

MutableIntList expected =
IntLists.mutable.with(1, 4, 9, 16, 25);

Assert.assertEquals(expected, mutable);
Assert.assertEquals(expected, immutable);
Assert.assertEquals(expected, lazy.toList());
}

Collecting from a primitive List (Java 10)

@Test
public void collectingFromAPrimitiveListJava10()
{
var mutableIntList = IntLists.mutable.with(1, 2, 3, 4, 5);
var immutableIntList = IntLists.immutable.with(1, 2, 3, 4, 5);

IntToIntFunction squared = i -> i * i;

var mutable =
mutableIntList.collectInt(squared, new IntArrayList());

var immutable =
immutableIntList.collectInt(squared, new IntArrayList())
.toImmutable();

var lazy = mutableIntList.asLazy().collectInt(squared);

var expected = IntLists.mutable.with(1, 4, 9, 16, 25);

Assert.assertEquals(expected, mutable);
Assert.assertEquals(expected, immutable);
Assert.assertEquals(expected, lazy.toList());
}

Notice that IntToIntFunction cannot be replaced with var. This is because a lambda must be assigned to some type.

Is it possible to collect selectively?

There is a method named collectIf which applies a Predicate first to each element, and then applies a Function to each element where the Predicate returned true. This method is a fused form of select and collect. It is also possible to just call select followed by collect either eagerly, lazily or in parallel.

@Test
public void collectingSelectively()
{
var executor = Executors.newWorkStealingPool();

var mutableList = mList(1, 2, 3, 4, 5);
var immutableList = iList(1, 2, 3, 4, 5);

Function<Integer, Integer> squared = i -> i * i;
Predicate<Integer> evens = i -> i % 2 ==0;

var mutable = mutableList.collectIf(evens, squared);

var immutable = immutableList.collectIf(evens, squared);

var lazy1 =
mutableList.asLazy().collectIf(evens, squared);
var lazy2 =
mutableList.asLazy().select(evens).collect(squared);

var parallel1 =
mutableList.asParallel(executor, 2)
.collectIf(evens, squared);

var parallel2 =
mutableList.asParallel(executor, 2)
.select(evens).collect(squared);

var expected = iList(4, 16);

Assert.assertEquals(expected, mutable);
Assert.assertEquals(expected, immutable);
Assert.assertEquals(expected, lazy1.toList());
Assert.assertEquals(expected, lazy2.toList());
Assert.assertEquals(expected, parallel1.toList());
Assert.assertEquals(expected, parallel2.toList());
}

Notice that Function and Predicate cannot be replaced with var. This is because a lambda must be assigned to some type.

APIs covered in the examples

  1. Collect (Eager, Lazy and Parallel) — transforms elements of a source collection to a new collection
  2. CollectIf (Eager, Lazy and Parallel) — transforms the elements of a source collection which satisfy a given predicate to a new collection
  3. mList — Creates a MutableList
  4. iList — Creates an ImmutableList
  5. IntLists.mutable.with — Creates a MutableIntList
  6. IntLists.immutable.with — Creates an ImmutableIntList
  7. asLazy — Returns a LazyIterable or LazyIntIterable
  8. asParallel — Returns a ParallelIterable
  9. toList — Converts the target Iterable into a MutableList
  10. var — Local variable Type Inference included in Java 10 (JEP 286)

Check out this presentation to learn more about the origins, design and evolution of the Eclipse Collections API. There is also a video covering the slides that was recorded at an Eclipse Community Virtual Meet-up.

Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.