Saturday, July 9, 2016

Part 2 : Writing custom collectors for Set implementations


The class CollectionCollector remains the same. We discussed class ToListCollector which creates a Collector of type ArrayList with initial capacity.

The perquisite to this article is previous article. The previous article will give you basics that we will use it in this article.
In this post will discuss ToSetCollectors for HashSet (with initial capacity), LinkedHashSet (with initial capacity), TreeSet (with Comparator).

For this custom collectors we will design 2 classes in fact, we will design just 1.
1.       CollectionCollector.java : We saw this class in previous post. You can refer previous post for this class. You can also view this class at Github.
2.       ToSetCollectors.java : This is a new class that will 3 methods. Methods are as follows:
a.       toHashSet(int initialcapacity)
b.       toLinkedHashSet(int initialCapacity)
c.       toTreeSet(Comparator<? super T> comparator)

Let us discuss ToSetCollectors class now.

Before we start discussing the methods of class ToSetCollectors we will define characteristics that we will use for Collectors.

private static final Set<Collector.Characteristics> CH_ID = Collections.unmodifiableSet(EnumSet.of(
Collector.Characteristics.IDENTITY_FINISH));
     
private static final Set<Collector.Characteristics> CH_UNORDERED_ID = Collections.unmodifiableSet(EnumSet.of(
Collector.Characteristics.UNORDERED,  Collector.Characteristics.IDENTITY_FINISH));

1.       toHashSet() method: Collectors.toSet() method allows you to collect elements from Stream in HashSet that Collector does not place any initial capacity while creating the HashSet. The capability of toHashSet method in class ToSetCollectors is that you can provide the initial capacity of HashSet.

       /**
       * Create a {@link Collector} of type {@link HashSet}
       * with initial capacity.
       *
       * @param <T> type of input elements for new Collector
       * */
      public static <T> Collector<T, ?, Set<T>> toHashSet(
                  final int initialCapacity) {
           
            return
                        CollectionCollector.toCollection(
                                    initialCapacity,
                                    HashSet::new,
                                    CH_UNORDERED_ID);
      }

The method just accepts the initial capacity as parameter. This method in turn calls CollectionCollector class’s method toCollection() that accepts initial capacity, IntFunction and Set<Collector.Characteristics> as parameters.

NOTE: IntFunction is a functional interface that represents an int-valued arguments and produces a result. And why do we care about it? Because it accepts the int-valued argument in our case it will be initial capacity and returns a result in our case it will be for example new ArrayList<>(initialCapacity).

Usage:

Assume you have List<Country> called countries. Now you want to add all Country names into a set. We can write something like this:

countries.map(Country::getName)
         .stream()
         .collect(ToSetCollectors.toHashSet(50));

2.       toLinkedHashSet(): This method is almost same as previous method.

      /**
       * Create a {@link Collector} of type {@link LinkedHashSet}
       * with initial capacity.
       *
       * @param <T> type of input elements for new Collector
       * */
      public static <T> Collector<T, ?, Set<T>> toLinkedHashSet(
                  final int initialCapacity) {
           
            return
                        CollectionCollector.toCollection(
                                    initialCapacity,
                                    LinkedHashSet::new,
                                    CH_ID);
      }

Usage:

Assume you have List<Country> called countries. Now you want to add all Country names into an ordered set which maintains insertion order. We can write something like this:

countries.map(Country::getName)
         .stream()
         .collect(ToSetCollectors.toLinkedHashSet(50));


3.       toTreeSet(): This method accepts Comparator as a parameter and not initial capacity. TreeSet class does not have any constructor that accepts initial capacity. This method will directly call CollectionCollector class’s toCollection method with 2 parameters. The 2 parameters are Supplier and Set<Collection.Characteristics>.
      /**
       * Create a {@link Collector} of type {@link TreeSet}
       *
       * All elements inserted into implement the
       * {@link Comparator} interface.
       *
       * @param <T> type of input elements of new Collector
       * */
      public static <T> Collector<T, ?, NavigableSet<T>> toTreeSet(
                  final Comparator<? super T> comparator) {
           
            return
                        CollectionCollector.toCollection(
                                    () -> new TreeSet<>(comparator),
                                    CH_ID);
      }

Usage:

Assume you have List<Country> called countries. Now you want to add all Country names into an ordered set which maintains elements by Comparator. We can write something like this:

countries.map(Country::getName)
         .stream()
         .collect(ToSetCollectors.toLinkedHashSet(50));


Entire class ToSetCollectors is below:

import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collector;

/**
 * {@link ToSetCollectors} is used to create {@link Collector}
 * that accepts initial capacity.
 * */
public final class ToSetCollectors {

       private static final Set<Collector.Characteristics> CH_ID =       Collections.unmodifiableSet(EnumSet.of(
Collector.Characteristics.IDENTITY_FINISH));
     
       private static final Set<Collector.Characteristics> CH_UNORDERED_ID =         Collections.unmodifiableSet(EnumSet.of(
Collector.Characteristics.UNORDERED,  Collector.Characteristics.IDENTITY_FINISH));
     
      /**
       * Create a {@link Collector} of type {@link HashSet}
       * with initial capacity.
       *
       * @param <T> type of input elements for new Collector
       * */
      public static <T> Collector<T, ?, Set<T>> toHashSet(
                  final int initialCapacity) {
           
            return
                        CollectionCollector.toCollection(
                                    initialCapacity,
                                    HashSet::new,
                                    CH_UNORDERED_ID);
      }
     
      /**
       * Create a {@link Collector} of type {@link LinkedHashSet}
       * with initial capacity.
       *
       * @param <T> type of input elements for new Collector
       * */
      public static <T> Collector<T, ?, Set<T>> toLinkedHashSet(
                  final int initialCapacity) {
           
            return
                        CollectionCollector.toCollection(
                                    initialCapacity,
                                    LinkedHashSet::new,
                                    CH_ID);
      }
     
      /**
       * Creates a {@link Collector} of type {@link TreeSet}
       *
       * All elements inserted into implement the
       * {@link Comparable} interface.
       *
       * @param <T> type of input elements for new Collector
       * */
      public static <T> Collector<T, ?, NavigableSet<T>> toTreeSet() {
           
            return
                        CollectionCollector.toCollection(
                                    TreeSet::new,
                                    CH_ID);
      }
     
      /**
       * Create a {@link Collector} of type {@link TreeSet}
       *
       * All elements inserted into implement the
       * {@link Comparator} interface.
       *
       * @param <T> type of input elements of new Collector
       * */
      public static <T> Collector<T, ?, NavigableSet<T>> toTreeSet(
                  final Comparator<? super T> comparator) {
           
            return
                        CollectionCollector.toCollection(
                                    () -> new TreeSet<>(comparator),
                                    CH_ID);
      }
}

In next post we will see Collectors of Google Guava Library.

If there are any mistakes or better way to do it, please mention in comments.


1 comment:

  1. Details view of the matter. information, i really like finding views that interesting and beneficial anyway. essay writing service uk

    ReplyDelete

Ads Inside Post