JVM Advent 2018

The JVM Programming Advent Calendar

Hidden Treasures of Eclipse Collections

Eclipse Collections is an open source Java Collections framework. Please refer to the resources at the end of the blog for more information about the framework. In this blog I am going to demonstrate five lesser known features of the framework.

  1. distinct(): When you want to get unique items in your List the typical way to get them is to add your List to a Set. However, you lose the original order and end up with an unpredictable order of a hash table. Sometimes, you need to preserve the order in which we have visited the unique elements. We developed distinct() for this use case. When you call distinct() on an Eclipse Collections MutableList, the result is a List of unique elements.
    @Test
    public void distinct()
    {
        MutableList<Integer> integers = Lists.mutable.with(
                1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
        Assert.assertEquals(
                Lists.mutable.with(1, 2, 3, 4), 
                integers.distinct());
    }

    If you cannot convert your original List into an Eclipse Collections List, you can use ListAdapter or ListIterate to get the same API.

    @Test
    public void distinctNonEclipseCollectionsList()
    {
        List<Integer> integersLinkedList = new LinkedList<>(integers);
        Assert.assertEquals(
                Lists.mutable.with(1, 2, 3, 4),
                ListAdapter.adapt(integersLinkedList).distinct());
        Assert.assertEquals(
                Lists.mutable.with(1, 2, 3, 4),
                ListIterate.distinct(integersLinkedList));
    }

    If you need distinct() to be available for lazy evaluation, it is available on our LazyIterable as well.

    @Test
    public void distinctAsLazy()
    {
        MutableList<String> distinctStrings = integers.asLazy()
                .distinct()
                .collect(String::valueOf)
                .toList();
        Assert.assertEquals(
                Lists.mutable.with("1", "2", "3", "4"),
                distinctStrings);
    }
  2. partition(): When you want to select and reject elements in a single pass based on a Predicate you can use partition()
    @Test
    public void partition()
    {
        MutableList<Integer> integers = Lists.mutable.with(
                1, 2, 3, 4, 5, 6, 7, 8, 9);
        PartitionMutableList<Integer> evenOddPartition = integers
                .partition(each -> each % 2 == 0);
        Assert.assertEquals(
                Lists.mutable.with(2, 4, 6, 8),
                evenOddPartition.getSelected());
        Assert.assertEquals(
                Lists.mutable.with(1, 3, 5, 7, 9),
                evenOddPartition.getRejected());
    }

    If you cannot use an Eclipse Collections interface, you can always wrap your collections with our adapters or use our static utility Iterate to get the same API.

    @Test
    public void partition()
    {
        List<Integer> integerList = new ArrayList<>(integers);
        PartitionMutableList<Integer> evenOddUsingAdapter =
                ListAdapter.adapt(integerList)
                        .partition(each -> each % 2 == 0);
        Assert.assertEquals(
                Lists.mutable.with(2, 4, 6, 8),
                evenOddUsingAdapter.getSelected());
        Assert.assertEquals(
                Lists.mutable.with(1, 3, 5, 7, 9),
                evenOddUsingAdapter.getRejected());
    
        PartitionIterable<Integer> evenOddUsingIterate =
            Iterate.partition(
                integerList,
                each -> each % 2 == 0);
        Assert.assertEquals(
                Lists.mutable.with(2, 4, 6, 8),
                evenOddUsingIterate.getSelected());
        Assert.assertEquals(
                Lists.mutable.with(1, 3, 5, 7, 9),
                evenOddUsingIterate.getRejected());
    }
  3. selectInstancesOf(): If you want to filter and return only the instances of a particular class you can use selectInstancesOf().
    @Test
    public void selectInstancesOf()
    {
        MutableList<Number> numbers = Lists.mutable.with(
                1.0, 2, 3.0, 4.0, 5);
        MutableList<Integer> integers = numbers
                .selectInstancesOf(Integer.class);
        Assert.assertEquals(Lists.mutable.with(2, 5), integers);
    }

    If you cannot use an Eclipse Collections interface, you can always wrap your collections with our adapters or use our static utility Iterate to get the same API.

    @Test
    public void selectInstancesOf()
    {
        List<Number> numberList = new ArrayList<>(numbers);
        MutableList<Integer> integersUsingAdapter = ListAdapter
                .adapt(numberList)
                .selectInstancesOf(Integer.class);
        Assert.assertEquals(
                Lists.mutable.with(2, 5), 
                integersUsingAdapter);
    
        Collection<Integer> integersUsingIterate = Iterate
                .selectInstancesOf(numberList, Integer.class);
        Assert.assertEquals(
                Lists.mutable.with(2, 5), 
                integersUsingIterate);
    }
  4. chunk(): If you want to divide your iterable into multiple iterables of a particular size, you can use chunk().
    @Test
    public void chunk()
    {
        MutableList<Integer> integers = Lists.mutable.with(
                1, 2, 3, 4, 5);
        MutableList<MutableList<Integer>> expectedChunked =
                Lists.mutable.with(
                        Lists.mutable.with(1, 2),
                        Lists.mutable.with(3, 4),
                        Lists.mutable.with(5));
        Assert.assertEquals(
                expectedChunked, 
                integers.chunk(2));
    }

    If you cannot use an Eclipse Collections interface, you can always wrap your collections with our adapters or use our static utility Iterate to get the same API.

    @Test
    public void chunk()
    {
        List<Integer> integerList = new ArrayList<>(integers);
    
        RichIterable<RichIterable&lt;Integer>> chunkUsingAdapter =
            ListAdapter
                .adapt(integerList)
                .chunk(2);
        Assert.assertEquals(
                expectedChunked,
                chunkUsingAdapter);
    
        RichIterable<RichIterable<Integer>> chunkUsingIterate = 
            Iterate
                .chunk(integerList, 2);
        Assert.assertEquals(
                expectedChunked,
                chunkUsingIterate);
    }
  5. as vs to naming convention: In Eclipse Collections, we try to follow common conventions like the ones described in this blog.In Eclipse Collections, methods that start with the word “as” always take constant time and create constant garbage. Usually that means returning a wrapper object. Some examples:
    • asUnmodifiable() – returns collection wrappers that throw on mutating methods
    • asSynchronized() – returns collection wrappers that grab a lock before delegating
    • asLazy() – returns a wrapper that supports lazy evaluation, by deferring evaluation of non-terminating operations and only evaluating when a terminating operation is encountered
    • asReversed() – returns a lazy wrapper around a list that iterates in reverse order when computation is forced
    • asParallel() (Beta) – returns a lazy wrapper that supports parallel execution

    In Eclipse Collections, methods that start with the word “to” can take more time and create more garbage. Most of the time that means creating a new collection in linear time. In the case of sorted collections, that grows to O(n log n). Some examples:

    • toList() – always creates a new copy, even when called on lists
    • toSet(), toBag(), toStack(), toMap(), toArray() –  O(n) in time and memory
    • toSortedList(), toSortedListBy(), toSortedSet(), toSortedSetBy(), toSortedMap() – O(n log n) time
    • toImmutable() – O(n) time on mutable collections
    • toReversed() – same as asReversed() but will have eager evaluation
    • toString() – yes, it counts 🙂

Summary:

In this blog I explained a few lesser known features of Eclipse Collections distinct(), partition(), selectInstancesOf(), chunk() and as() vs to() method naming conventions.

I hope you found the post informative. If you have not used Eclipse Collections before, give it a try. There are few resources below. Make sure you show us your support and put a star on our GitHub Repository

Eclipse Collections Resources:
Eclipse Collections comes with it’s own implementations of List, Set and Map. It also has additional data structures like Multimap, Bag and an entire Primitive Collections hierarchy. Each of our collections have a rich API for commonly required iteration patterns.

Author: Nikhil Nanivadekar

Lead Eclipse Collections: eclipse.org/collections, Java Champion. I enjoy hiking, skiing, reading. All opinions stated by me are my own.

Next Post

Previous Post

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2019 JVM Advent 2018

Theme by Anders Norén

%d bloggers like this: