Create own collectors

Sometimes it is useful to be able perform several actions extracting several actions with a stream pass. It can be achieved building our own collector. For example, suppose we need to get the maximal and minimal values of a series. So can we achieve it using collectors.

public class MaxMinCollector2 implements Collector<Integer, MaxMinContainer, MaxMinContainer>{

    public void accumulate(MaxMinContainer container, Integer val){

        if(container.max == null){
            container.max = val;
        }else if(container.max < val){
            container.max = val;
        }

        if(container.min == null){
            container.min = val;
        }else if(container.min > val){
            container.min = val;
        }

    }

    public MaxMinContainer combine(MaxMinContainer a, MaxMinContainer b){
        if(a.max == null){
            b.getMax().ifPresent(v -> a.max = v);
        }else {
            b.getMax().ifPresent(v -> a.max = a.max < v ? v : a.max);
        }

        if(a.min == null){
            b.getMin().ifPresent(v -> a.min = v);
        }else {
            b.getMax().ifPresent(v -> a.min = a.min > v ? v : a.min);
        }

        return a;
    }

    @Override
    public Supplier<MaxMinContainer> supplier() {
        return MaxMinContainer::new;
    }

    @Override
    public BiConsumer<MaxMinContainer, Integer> accumulator() {
        return this::accumulate;
    }

    @Override
    public BinaryOperator<MaxMinContainer> combiner() {
        return this::combine;
    }

    @Override
    public Function<MaxMinContainer, MaxMinContainer> finisher() {
        return (a) -> a;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return new HashSet<>(Arrays.asList(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED));
    }
}

and its corresponding test:

package de.lacambra.utils.collectors;

import org.junit.Before;
import org.junit.Test;

import java.util.stream.IntStream;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class MaxMinCollectorTest {

    MaxMinCollector cut;

    @Before
    public void setUp() throws Exception {
        cut = new MaxMinCollector();
    }

    @Test
    public void testMaxMinSerie() {

        MaxMinCollector result = IntStream.of(1, 2, 3, 4, 5, 6)
                .collect(MaxMinCollector::new, MaxMinCollector::accumulate, MaxMinCollector::combine);

        assertThat(result.getMax().get(), is(6));
        assertThat(result.getMin().get(), is(1));

        result = IntStream.of(1000, 2, 3342, 421, 523, 6)
                .collect(MaxMinCollector::new, MaxMinCollector::accumulate, MaxMinCollector::combine);

        assertThat(result.getMax().get(), is(3342));
        assertThat(result.getMin().get(), is(2));
    }

    @Test
    public void emptySerie(){
        MaxMinCollector result = IntStream.of()
                .collect(MaxMinCollector::new, MaxMinCollector::accumulate, MaxMinCollector::combine);

        assertThat(result.getMax().isPresent(), is(false));
        assertThat(result.getMin().isPresent(), is(false));
    }

    @Test
    public void oneValueSerie(){
        MaxMinCollector result = IntStream.of(34)
                .collect(MaxMinCollector::new, MaxMinCollector::accumulate, MaxMinCollector::combine);

        assertThat(result.getMax().get(), is(34));
        assertThat(result.getMin().get(), is(34));
    }
}

Leave a Reply