All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.digipost.DiggCollectors Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) Posten Norge AS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package no.digipost;

import no.digipost.collection.AdaptableCollector;
import no.digipost.collection.EnforceAtMostOneElementCollector;
import no.digipost.concurrent.OneTimeAssignment;
import no.digipost.tuple.Tuple;
import no.digipost.tuple.ViewableAsTuple;
import no.digipost.util.ViewableAsOptional;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Collections.unmodifiableList;

/**
 * Various {@link java.util.stream.Collector} implementations.
 */
@SuppressWarnings("deprecation")
public final class DiggCollectors {

    /**
     * A multimap maps from keys to lists, and this collector will arrange {@link ViewableAsTuple tuples}
     * by putting each distinct {@link Tuple#first() first tuple-element} as keys of the resulting map, mapping
     * them to a {@link List}, and adding each {@link Tuple#second() second tuple-element} to the list.
     *
     * @param  The type of the first tuple element, which will become the key type of the resulting {@code Map}.
     * @param  The type of the second tuple element, which will become the {@code List} value type of the
     *             resulting {@code Map}.
     *
     * @return the multimap collector.
     */
    public static  AdaptableCollector>, ?, Map>> toMultimap() {
        Function>, Tuple>> asTuple = ViewableAsTuple::asTuple;
        return toMultimap(asTuple.andThen(Tuple::first), asTuple.andThen(Tuple::second));
    }

    public static  AdaptableCollector>> toMultimap(Function> extractor) {
        return toMultimap(Function.identity(), extractor);
    }

    public static  AdaptableCollector>> toMultimap(Function keyExtractor, Function> extractor) {
        return adapt(Collectors.toMap(keyExtractor, extractor.andThen(DiggOptionals::toList), DiggCollectors::concat));
    }


    /**
     * This is a collector for accessing the expected singular only element of a {@link Stream}, as
     * it will throw an exception if more than one element is processed. This should be used in
     * preference of the {@link Stream#findFirst()} or {@link Stream#findAny()} when it is imperative
     * that the stream indeed yields a maximum of one single element, and any more elements is
     * considered a programming error.
     *
     * @return the collector
     */
    public static  AdaptableCollector, Optional> allowAtMostOne() {
        return allowAtMostOneOrElseThrow(ViewableAsOptional.TooManyElements::new);
    }

    /**
     * This is a collector for accessing the expected singular only element of a {@link Stream}, as
     * it will throw the exception yielded from the given function if more than one element is processed.
     *
     * @param the function will be given the first element yielded from the stream as its first argument
     *                     and the unexpected excess one as the second, which may be used to construct an
     *                     exception to be thrown.
     * @return the collector
     * @see #allowAtMostOne()
     */
    public static  AdaptableCollector, Optional> allowAtMostOneOrElseThrow(BiFunction exceptionOnExcessiveElements) {
        return adapt(new EnforceAtMostOneElementCollector<>(exceptionOnExcessiveElements));
    }


    /**
     * Turn any {@link Collector} into an {@link AdaptableCollector}.
     *
     * @param collector the collector to convert
     *
     * @return the {@link AdaptableCollector}
     *
     * @see AdaptableCollector
     * @deprecated Use {@link Collectors#collectingAndThen(Collector, Function)} instead.
     */
    @Deprecated
    public static  AdaptableCollector adapt(Collector collector) {
        if (collector instanceof AdaptableCollector) {
            return (AdaptableCollector) collector;
        } else {
            return AdaptableCollector.of(collector.supplier(), collector.accumulator(), collector.combiner(), collector.finisher(), collector.characteristics());
        }
    }



    private static  List concat(Collection list1, Collection list2) {
        List newList = new ArrayList<>(list1.size() + list2.size());
        newList.addAll(list1);
        newList.addAll(list2);
        return unmodifiableList(newList);
    }

    private DiggCollectors() {}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy