StreamUtils.java
- package no.nav.data.common.utils;
- import lombok.SneakyThrows;
- import no.nav.data.common.exceptions.NotFoundException;
- import org.springframework.core.io.ClassPathResource;
- import java.nio.charset.StandardCharsets;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Optional;
- import java.util.Set;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.function.Function;
- import java.util.function.Predicate;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- import java.util.stream.StreamSupport;
- import static java.util.Comparator.comparing;
- import static java.util.function.Function.identity;
- import static java.util.stream.Collectors.toList;
- public final class StreamUtils {
- private StreamUtils() {
- }
- /**
- * Get change in two collections based on predicate to match equality
- *
- * @param before collection before
- * @param after collection after
- * @param comparator function to compare if elements are equal
- * @param <T> the type of the collections
- */
- public static <T> CollectionDifference<T> difference(Collection<T> before, Collection<T> after, Comparator<? super T> comparator) {
- List<T> removed = new ArrayList<>(before);
- List<T> shared = new ArrayList<>();
- List<T> added = new ArrayList<>(after);
- removed.removeIf(beforeElement -> {
- for (T afterElement : after) {
- if (comparator.compare(beforeElement, afterElement) == 0) {
- shared.add(afterElement);
- added.remove(afterElement);
- return true;
- }
- }
- return false;
- });
- return new CollectionDifference<>(new ArrayList<>(before), new ArrayList<>(after), removed, shared, added);
- }
- public static <T extends Comparable<T>> CollectionDifference<T> difference(Collection<T> before, Collection<T> after) {
- return difference(before, after, comparing(identity()));
- }
- public static <T> Stream<T> safeStream(Iterable<T> iterable) {
- return iterable == null ? Stream.empty() : StreamSupport.stream(iterable.spliterator(), false);
- }
- public static <T> List<T> nullToEmptyList(Collection<T> list) {
- return list == null ? Collections.emptyList() : new ArrayList<>(list);
- }
- public static <T> List<T> copyOf(List<T> list) {
- return list == null ? Collections.emptyList() : List.copyOf(list);
- }
- @SafeVarargs
- public static <T> List<T> union(List<? extends T>... lists) {
- ArrayList<T> list = new ArrayList<>();
- for (List<? extends T> l : lists) {
- list.addAll(l);
- }
- return list;
- }
- public static <K, V> Map<K, V> toMap(Iterable<V> from, Function<? super V, K> keyExtractor) {
- return safeStream(from).collect(Collectors.toMap(keyExtractor, Function.identity()));
- }
- public static <T> List<T> distinctByKey(Iterable<T> from, Function<? super T, ?> keyExtractor) {
- return filter(from, distinctByKey(keyExtractor));
- }
- public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
- Set<Object> seen = ConcurrentHashMap.newKeySet();
- return t -> seen.add(keyExtractor.apply(t));
- }
- public static <T, F> List<T> convert(Collection<F> from, Function<F, T> converter) {
- return safeStream(from).map(converter).filter(Objects::nonNull).collect(toList());
- }
- public static <T, F> List<T> convertFlat(Collection<F> from, Function<F, Collection<T>> converter) {
- return safeStream(from).map(converter).filter(Objects::nonNull).flatMap(Collection::stream).collect(toList());
- }
- @SafeVarargs
- public static <T, F> List<T> applyAll(Collection<F> from, Function<F, Collection<T>>... converters) {
- return Stream.of(converters)
- .map(f -> convert(from, f))
- .flatMap(Collection::stream)
- .flatMap(Collection::stream)
- .collect(toList());
- }
- @SafeVarargs
- public static <T, F> List<T> applyAll(F from, Function<F, Collection<T>>... converters) {
- return Stream.of(converters)
- .map(f -> f.apply(from))
- .flatMap(Collection::stream)
- .collect(toList());
- }
- public static <T> List<T> filter(Iterable<T> objects, Predicate<T> filter) {
- return safeStream(objects).filter(filter).collect(toList());
- }
- public static <T, U extends Comparable<? super U>> List<T> filterCommonElements(Iterable<T> objects, Iterable<T> compareToObjects,
- Function<? super T, ? extends U> keyExtractor) {
- var comparator = Comparator.comparing(keyExtractor);
- return filter(objects, object -> safeStream(compareToObjects).noneMatch(other -> comparator.compare(object, other) == 0));
- }
- public static <T> T find(Iterable<T> objects, Predicate<T> filter) {
- return safeStream(objects).filter(filter).findFirst().orElseThrow(() -> new NotFoundException("could not find item"));
- }
- public static <T> Optional<T> tryFind(Iterable<T> objects, Predicate<T> filter) {
- return safeStream(objects).filter(filter).findFirst();
- }
- @SafeVarargs
- public static <T> T first(T... objects) {
- return Stream.of(objects).filter(Objects::nonNull).findFirst().orElseThrow();
- }
- public static <T> T firstOrNull(Collection<T> objects) {
- return safeStream(objects).findFirst().orElse(null);
- }
- @SneakyThrows
- public static String readCpFile(String path) {
- return org.springframework.util.StreamUtils.copyToString(new ClassPathResource(path).getInputStream(), StandardCharsets.UTF_8);
- }
- public static <T> boolean duplicates(Collection<T> items, Function<? super T, ?> keyExctactor) {
- var distinct = distinctByKey(items, keyExctactor);
- return distinct.size() != items.size();
- }
- }