
org.whaka.util.function.MapStream Maven / Gradle / Ivy
package org.whaka.util.function;
import static org.whaka.util.UberMaps.*;
import static org.whaka.util.UberPredicates.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import org.whaka.util.UberMaps;
import org.whaka.util.UberMaps.Entry;
public class MapStream implements Stream> {
private final Stream> actual;
public MapStream(Map map) {
this(map.entrySet().stream());
}
public MapStream(Stream extends Map.Entry> actual) {
this.actual = actual.map(UberMaps::entry);
}
private Stream> getActual() {
return actual;
}
@Override
public Iterator> iterator() {
return getActual().iterator();
}
@Override
public Spliterator> spliterator() {
return getActual().spliterator();
}
@Override
public boolean isParallel() {
return getActual().isParallel();
}
@Override
public MapStream sequential() {
return new MapStream<>(getActual().sequential());
}
@Override
public MapStream parallel() {
return new MapStream<>(getActual().parallel());
}
@Override
public MapStream unordered() {
return new MapStream<>(getActual().unordered());
}
@Override
public MapStream onClose(Runnable closeHandler) {
return new MapStream<>(getActual().onClose(closeHandler));
}
@Override
public void close() {
getActual().close();
}
@Override
public MapStream filter(Predicate super UberMaps.Entry> predicate) {
return new MapStream<>(getActual().filter(predicate));
}
/**
* Each entry in the stream are matched as key/value pair against the specified predicate.
* Only the successfully matched entries are retained in the stream.
*/
public MapStream filter(BiPredicate predicate) {
return filter(e -> predicate.test(e.key, e.val));
}
/**
* Filter out only the entries where key matches specified predicate.
*/
public MapStream filterKey(Predicate super K> keyPredicate) {
return filter(e -> keyPredicate.test(e.key));
}
/**
* Filter out only the entries where value matches specified predicate.
*/
public MapStream filterValue(Predicate super V> valPredicate) {
return filter(e -> valPredicate.test(e.val));
}
/**
* Filter only the keys that are instances of the specified class (or nulls) and cast them to the specified type.
*
*
Note: nulls
survive the filtering!
* Use separate filters to drop nulls!
*/
public MapStream filterKeyByClass(Class filteredKeyClass) {
return filterKey(createIsNullOrInstancePredicate(filteredKeyClass)).mapKey(filteredKeyClass::cast);
}
/**
* Filter only the values that are instances of the specified class (or nulls) and cast them to the specified type.
*
*
Note: nulls
survive the filtering!
* Use separate filters to drop nulls!
*/
public MapStream filterValueByClass(Class filteredValueClass) {
return filterValue(createIsNullOrInstancePredicate(filteredValueClass)).mapValue(filteredValueClass::cast);
}
private static Predicate createIsNullOrInstancePredicate(Class> predicatedClass) {
return anyOf(Objects::isNull, predicatedClass::isInstance);
}
/**
* All the entries that do match specified predicate are removed from the stream.
*/
public MapStream drop(Predicate super UberMaps.Entry> predicate) {
return filter(not(predicate));
}
/**
* Each entry in the stream are matched as key/value pair against the specified predicate.
* All the successfully matched entries are removed from the stream.
*/
public MapStream drop(BiPredicate predicate) {
return drop(e -> predicate.test(e.key, e.val));
}
/**
* All the entries where key matches specified predicate are removed from the stream.
*/
public MapStream dropKey(Predicate super K> keyPredicate) {
return filterKey(not(keyPredicate));
}
/**
* All the entries where value matches specified predicate are removed from the stream.
*/
public MapStream dropValue(Predicate super V> valPredicate) {
return filterValue(not(valPredicate));
}
@Override
public UberStream map(Function super UberMaps.Entry, ? extends R> mapper) {
return new UberStream<>(getActual().map(mapper));
}
/**
* Each entry in the stream is mapped by the specified function into another entry.
*/
public MapStream mapEntry(Function super UberMaps.Entry, ? extends Map.Entry> mapper) {
return new MapStream<>(getActual().map(mapper));
}
/**
* Each key/value pair in the stream is mapped by the specified BiFunction into another entry.
*/
public MapStream mapEntry(BiFunction> mapper) {
return mapEntry(e -> mapper.apply(e.key, e.val));
}
/**
* For each entry in the stream - key is mapped by the specified key mapper function, and value is mapped
* by the specified value mapper function.
*/
public MapStream mapEntry(Function super K, ? extends K2> keyMapper, Function super V, ? extends V2> valMapper) {
return mapEntry((k,v) -> entry(keyMapper.apply(k), valMapper.apply(v)));
}
/**
* For each entry in the stream - key is mapped by the specified key mapper function, value is untouched.
*/
public MapStream mapKey(Function super K, ? extends K2> keyMapper) {
return mapEntry(keyMapper, Function.identity());
}
/**
* For each entry in the stream - key is untouched, and value is mapped by the specified value mapper function.
*/
public MapStream mapValue(Function super V, ? extends V2> valMapper) {
return mapEntry(Function.identity(), valMapper);
}
@Override
public IntStream mapToInt(ToIntFunction super UberMaps.Entry> mapper) {
return getActual().mapToInt(mapper);
}
@Override
public LongStream mapToLong(ToLongFunction super UberMaps.Entry> mapper) {
return getActual().mapToLong(mapper);
}
@Override
public DoubleStream mapToDouble(ToDoubleFunction super UberMaps.Entry> mapper) {
return getActual().mapToDouble(mapper);
}
@Override
public UberStream flatMap(Function super UberMaps.Entry, ? extends Stream extends R>> mapper) {
return new UberStream<>(getActual().flatMap(mapper));
}
/**
* Each entry in the stream is mapped by the specified function into another map. Then each produced map
* is flattened into a stream of entries, and they are combined into a single resulting stream.
*/
public MapStream flatMapEntry(Function super UberMaps.Entry, ? extends Map> mapper) {
return new MapStream<>(getActual().flatMap(e -> mapper.apply(e).entrySet().stream()));
}
/**
* For each entry in the stream - key is mapped by the specified function into a collection.
* Then result stream is mapped into stream of map entries where keys are stream elements, and values are
* the value of the original key. For example:
*
* Map map = {1=10, 2=20};
* Map map2 = new MapStream(map).flatMapKey(i -> asList(i, i * 10)).collect();
* System.out.println(map2); // {1=10, 10=10, 2=20, 20=20}
*
*/
public MapStream flatMapKey(Function super K, ? extends Collection extends K2>> mapper) {
return flatMapEntry(e -> new MapStream<>(mapper.apply(e.key).stream().map(k -> UberMaps.entry(k, e.val))).toMap());
}
@Override
public IntStream flatMapToInt(Function super UberMaps.Entry, ? extends IntStream> mapper) {
return getActual().flatMapToInt(mapper);
}
@Override
public LongStream flatMapToLong(Function super UberMaps.Entry, ? extends LongStream> mapper) {
return getActual().flatMapToLong(mapper);
}
@Override
public DoubleStream flatMapToDouble(Function super UberMaps.Entry, ? extends DoubleStream> mapper) {
return getActual().flatMapToDouble(mapper);
}
@Override
public MapStream distinct() {
return new MapStream<>(getActual().distinct());
}
/**
* Only the entries with unique value are preserved in the stream.
*/
public MapStream distinctValues() {
Set set = new HashSet<>();
return filterValue(set::add);
}
@Override
public MapStream sorted() {
return new MapStream<>(getActual().sorted());
}
@Override
public MapStream sorted(Comparator super UberMaps.Entry> comparator) {
return new MapStream<>(getActual().sorted(comparator));
}
/**
* All entries in the stream are sorted by comparing keys using specified comparator.
*/
public MapStream sortedKeys(Comparator super K> comparator) {
return sorted(Map.Entry.comparingByKey(comparator));
}
/**
* All entries in the stream are sorted by comparing values using specified comparator.
*/
public MapStream sortedValues(Comparator super V> comparator) {
return sorted(Map.Entry.comparingByValue(comparator));
}
@Override
public MapStream peek(Consumer super UberMaps.Entry> action) {
return new MapStream<>(getActual().peek(action));
}
/**
* Specified consumer are called for each key in the stream.
*/
public MapStream peekKeys(Consumer super K> action) {
return peek(e -> action.accept(e.key));
}
/**
* Specified consumer are called for each value in the stream.
*/
public MapStream peekValues(Consumer super V> action) {
return peek(e -> action.accept(e.val));
}
@Override
public MapStream limit(long maxSize) {
return new MapStream<>(getActual().limit(maxSize));
}
@Override
public MapStream skip(long n) {
return new MapStream<>(getActual().skip(n));
}
@Override
public void forEach(Consumer super UberMaps.Entry> action) {
getActual().forEach(action);
}
/**
* Each entry in the stream are passed as key/value pair into the specified consumer.
*/
public void forEach(BiConsumer action) {
forEach(e -> action.accept(e.key, e.val));
}
/**
* Specified consumer are called for each key in the stream.
*/
public void forEachKey(Consumer super K> action) {
getActual().forEach(e -> action.accept(e.key));
}
/**
* Specified consumer are called for each value in the stream.
*/
public void forEachValue(Consumer super V> action) {
getActual().forEach(e -> action.accept(e.val));
}
@Override
public void forEachOrdered(Consumer super UberMaps.Entry> action) {
getActual().forEachOrdered(action);
}
/**
* Map all entries in the stream by {@link Entry#getKey()} method.
*/
public UberStream toKeys() {
return map(Entry::getKey);
}
/**
* Map all entries in the stream by {@link Entry#getValue()} method.
*/
public UberStream toValues() {
return map(Entry::getValue);
}
@Override
public Object[] toArray() {
return getActual().toArray();
}
@Override
public A[] toArray(IntFunction generator) {
return getActual().toArray(generator);
}
@Override
public UberMaps.Entry reduce(UberMaps.Entry identity, BinaryOperator> accumulator) {
return getActual().reduce(identity, accumulator);
}
@Override
public Optional> reduce(BinaryOperator> accumulator) {
return getActual().reduce(accumulator);
}
@Override
public U reduce(U identity, BiFunction, U> accumulator, BinaryOperator combiner) {
return getActual().reduce(identity, accumulator, combiner);
}
/**
* Collect stream back to the map form. No additional parameters required, for map is built from the entries.
* @see MapCollectors#toMap()
*/
public Map toMap() {
return getActual().collect(MapCollectors.toMap());
}
/**
* Collect stream to the linked map. No additional parameters required, for map is built from the entries.
* @see MapCollectors#toMap()
*/
public Map toLinkedMap() {
return to(LinkedHashMap::new);
}
/**
* Collect stream into a map provided by the specified supplier.
* No additional parameters required, for map is built from the entries.
* @see MapCollectors#toMap()
*/
public > M to(Supplier mapSupplier) {
return getActual().collect(MapCollectors.toMap(mapSupplier));
}
@Override
public R collect(Supplier supplier, BiConsumer> accumulator, BiConsumer combiner) {
return getActual().collect(supplier, accumulator, combiner);
}
@Override
public R collect(Collector super UberMaps.Entry, A, R> collector) {
return getActual().collect(collector);
}
@Override
public Optional> min(Comparator super UberMaps.Entry> comparator) {
return getActual().min(comparator);
}
@Override
public Optional> max(Comparator super UberMaps.Entry> comparator) {
return getActual().max(comparator);
}
@Override
public long count() {
return getActual().count();
}
@Override
public boolean anyMatch(Predicate super UberMaps.Entry> predicate) {
return getActual().anyMatch(predicate);
}
@Override
public boolean allMatch(Predicate super UberMaps.Entry> predicate) {
return getActual().allMatch(predicate);
}
@Override
public boolean noneMatch(Predicate super UberMaps.Entry> predicate) {
return getActual().noneMatch(predicate);
}
@Override
public Optional> findFirst() {
return getActual().findFirst();
}
@Override
public Optional> findAny() {
return getActual().findAny();
}
/**
* Find first entry that matches specified predicate.
*/
public Optional> find(Predicate super UberMaps.Entry> predicate) {
return filter(predicate).findFirst();
}
/**
* Find first entry where key matches specified predicate.
*/
public Optional> findKey(Predicate super K> keyPredicate) {
return filterKey(keyPredicate).findFirst();
}
/**
* Find first entry where key is equal to the specified object.
*/
public Optional> findByKey(K key) {
return findKey(Predicate.isEqual(key));
}
}