javaslang.collection.Map Maven / Gradle / Ivy
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2016 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.collection;
import javaslang.Function1;
import javaslang.Tuple2;
import javaslang.Tuple3;
import javaslang.control.Option;
import java.util.*;
import java.util.function.*;
/**
* An immutable {@code Map} interface.
*
* @param Key type
* @param Value type
* @author Daniel Dietrich, Ruslan Sennov
* @since 2.0.0
*/
public interface Map extends Traversable>, Function1 {
long serialVersionUID = 1L;
/**
* Narrows a widened {@code Map extends K, ? extends V>} to {@code Map}
* by performing a type safe-cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param map A {@code Map}.
* @param Key type
* @param Value type
* @return the given {@code map} instance as narrowed type {@code Map}.
*/
@SuppressWarnings("unchecked")
static Map narrow(Map extends K, ? extends V> map) {
return (Map) map;
}
@Override
default V apply(K key) {
return get(key).getOrElseThrow(NoSuchElementException::new);
}
/**
* Maps this {@code Map} to a new {@code Map} with different component type by applying a function to its elements.
*
* @param key's component type of the map result
* @param value's component type of the map result
* @param keyMapper a {@code Function} that maps the keys of type {@code K} to keys of type {@code K2}
* @param valueMapper a {@code Function} that the values of type {@code V} to values of type {@code V2}
* @return a new {@code Map}
* @throws NullPointerException if {@code keyMapper} or {@code valueMapper} is null
*/
Map bimap(Function super K, ? extends K2> keyMapper, Function super V, ? extends V2> valueMapper);
/**
* Returns true
if this map contains a mapping for the specified key.
*
* @param key key whose presence in this map is to be tested
* @return true
if this map contains a mapping for the specified key
*/
boolean containsKey(K key);
/**
* Returns true
if this map maps one or more keys to the
* specified value. This operation will require time linear in the map size.
*
* @param value value whose presence in this map is to be tested
* @return true
if this map maps one or more keys to the
* specified value
*/
default boolean containsValue(V value) {
return iterator().map(Tuple2::_2).contains(value);
}
/**
* FlatMaps this {@code Map} to a new {@code Map} with different component type.
*
* @param mapper A mapper
* @param key's component type of the mapped {@code Map}
* @param value's component type of the mapped {@code Map}
* @return A new {@code Map}.
* @throws NullPointerException if {@code mapper} is null
*/
Map flatMap(BiFunction super K, ? super V, ? extends Iterable>> mapper);
/**
* Returns the {@code Some} of value to which the specified key
* is mapped, or {@code None} if this map contains no mapping for the key.
*
* @param key the key whose associated value is to be returned
* @return the {@code Some} of value to which the specified key
* is mapped, or {@code None} if this map contains no mapping
* for the key
*/
Option get(K key);
/**
* Returns the keys contained in this map.
*
* @return {@code Set} of the keys contained in this map.
*/
Set keySet();
/**
* Maps the entries of this {@code Map} to form a new {@code Map}.
*
* @param key's component type of the map result
* @param value's component type of the map result
* @param mapper a {@code Function} that maps entries of type {@code (K, V)} to entries of type {@code (K2, V2)}
* @return a new {@code Map}
* @throws NullPointerException if {@code mapper} is null
*/
Map map(BiFunction super K, ? super V, Tuple2> mapper);
/**
* Maps the values of this {@code Map} while preserving the corresponding keys.
*
* @param the new value type
* @param valueMapper a {@code Function} that maps values of type {@code V} to values of type {@code V2}
* @return a new {@code Map}
* @throws NullPointerException if {@code valueMapper} is null
*/
Map mapValues(Function super V, ? extends V2> valueMapper);
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old value is
* replaced by the specified value.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return A new Map containing these elements and that entry.
*/
Map put(K key, V value);
/**
* Convenience method for {@code put(entry._1, entry._2)}.
*
* @param entry A Map.Tuple2
* @return A new Map containing these elements and that entry.
*/
Map put(Tuple2 extends K, ? extends V> entry);
/**
* Removes the mapping for a key from this map if it is present.
*
* @param key key whose mapping is to be removed from the map
* @return A new Map containing these elements without the entry
* specified by that key.
*/
Map remove(K key);
/**
* Removes the mapping for a key from this map if it is present.
*
* @param keys keys are to be removed from the map
* @return A new Map containing these elements without the entries
* specified by that keys.
*/
Map removeAll(Iterable extends K> keys);
@Override
int size();
/**
* Converts this Javaslang {@code Map} to a {@code java.util.Map} while preserving characteristics
* like insertion order ({@code LinkedHashMap}) and sort order ({@code SortedMap}).
*
* @return a new {@code java.util.Map} instance
*/
java.util.Map toJavaMap();
/**
* Transforms this {@code Map}.
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
default U transform(Function super Map, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
default Seq traverse(BiFunction mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return foldLeft(List.empty(), (acc, entry) -> acc.append(mapper.apply(entry._1, entry._2)));
}
default Tuple2, Seq> unzip(BiFunction super K, ? super V, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
return unzip(entry -> unzipper.apply(entry._1, entry._2));
}
default Tuple3, Seq, Seq> unzip3(BiFunction super K, ? super V, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
return unzip3(entry -> unzipper.apply(entry._1, entry._2));
}
Seq values();
// -- Adjusted return types of Traversable methods
@Override
default boolean contains(Tuple2 element) {
return get(element._1).map(v -> Objects.equals(v, element._2)).getOrElse(false);
}
@Override
Map distinct();
@Override
Map distinctBy(Comparator super Tuple2> comparator);
@Override
Map distinctBy(Function super Tuple2, ? extends U> keyExtractor);
@Override
Map drop(long n);
@Override
Map dropRight(long n);
@Override
Map dropUntil(Predicate super Tuple2> predicate);
@Override
Map dropWhile(Predicate super Tuple2> predicate);
@Override
Map filter(Predicate super Tuple2> predicate);
/**
* Flat-maps this entries to a sequence of values.
*
* Please use {@link #flatMap(BiFunction)} if the result should be a {@code Map}
*
* @param mapper A mapper
* @param Component type
* @return A sequence of flat-mapped values.
*/
@SuppressWarnings("unchecked")
@Override
default Seq flatMap(Function super Tuple2, ? extends Iterable extends U>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
// don't remove cast, doesn't compile in Eclipse without it
return (Seq) iterator().flatMap(mapper).toStream();
}
@Override
default U foldRight(U zero, BiFunction super Tuple2, ? super U, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return iterator().foldRight(zero, f);
}
@Override
Map> groupBy(Function super Tuple2, ? extends C> classifier);
@Override
Iterator extends Map> grouped(long size);
@Override
default boolean hasDefiniteSize() {
return true;
}
@Override
Map init();
@Override
Option extends Map> initOption();
@Override
default boolean isTraversableAgain() {
return true;
}
@Override
Iterator> iterator();
@Override
default int length() {
return size();
}
/**
* Maps the {@code Map} entries to a sequence of values.
*
* Please use {@link #map(BiFunction)} if the result has to be of type {@code Map}.
*
* @param mapper A mapper
* @param Component type
* @return A sequence of mapped values.
*/
@SuppressWarnings("unchecked")
@Override
default Seq map(Function super Tuple2, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
// don't remove cast, doesn't compile in Eclipse without it
return (Seq) iterator().map(mapper).toStream();
}
/**
* Creates a new map which by merging the entries of {@code this} map and {@code that} map.
*
* If collisions occur, the value of {@code this} map is taken.
*
* @param that the other map
* @return A merged map
* @throws NullPointerException if that map is null
*/
Map merge(Map extends K, ? extends V> that);
/**
* Creates a new map which by merging the entries of {@code this} map and {@code that} map.
*
* Uses the specified collision resolution function if two keys are the same.
* The collision resolution function will always take the first argument from this
map
* and the second from that
map.
*
* @param value type of that Map
* @param that the other map
* @param collisionResolution the collision resolution function
* @return A merged map
* @throws NullPointerException if that map or the given collision resolution function is null
*/
Map merge(Map extends K, U> that, BiFunction super V, ? super U, ? extends V> collisionResolution);
@Override
Tuple2 extends Map, ? extends Map> partition(Predicate super Tuple2> predicate);
@Override
Map peek(Consumer super Tuple2> action);
@Override
Map replace(Tuple2 currentElement, Tuple2 newElement);
@Override
Map replaceAll(Tuple2 currentElement, Tuple2 newElement);
@Override
Map retainAll(Iterable extends Tuple2> elements);
@Override
Map scan(Tuple2 zero,
BiFunction super Tuple2, ? super Tuple2, ? extends Tuple2> operation);
@Override
default Seq scanLeft(U zero, BiFunction super U, ? super Tuple2, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanLeft(this, zero, operation, List.empty(), List::prepend, List::reverse);
}
@Override
default Seq scanRight(U zero, BiFunction super Tuple2, ? super U, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanRight(this, zero, operation, List.empty(), List::prepend, Function.identity());
}
@Override
Iterator extends Map> sliding(long size);
@Override
Iterator extends Map> sliding(long size, long step);
@Override
Tuple2 extends Map, ? extends Map> span(Predicate super Tuple2> predicate);
@Override
default Spliterator> spliterator() {
return Spliterators.spliterator(iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
}
@Override
Map tail();
@Override
Option extends Map> tailOption();
@Override
Map take(long n);
@Override
Map takeRight(long n);
@Override
Map takeUntil(Predicate super Tuple2> predicate);
@Override
Map takeWhile(Predicate super Tuple2> predicate);
@Override
default Tuple2, Seq> unzip(Function super Tuple2, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
return iterator().unzip(unzipper).map(Stream::ofAll, Stream::ofAll);
}
@Override
default Tuple3, Seq, Seq> unzip3(
Function super Tuple2, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
return iterator().unzip3(unzipper).map(Stream::ofAll, Stream::ofAll, Stream::ofAll);
}
@Override
default Seq, U>> zip(Iterable extends U> that) {
Objects.requireNonNull(that, "that is null");
return Stream.ofAll(iterator().zip(that));
}
@Override
default Seq, U>> zipAll(Iterable extends U> that, Tuple2 thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
return Stream.ofAll(iterator().zipAll(that, thisElem, thatElem));
}
@Override
default Seq, Long>> zipWithIndex() {
return Stream.ofAll(iterator().zipWithIndex());
}
/**
* Performs an action on key, value pair.
*
* @param action A {@code BiConsumer}
* @throws NullPointerException if {@code action} is null
*/
default void forEach(BiConsumer action) {
Objects.requireNonNull(action, "action is null");
for (Tuple2 t : this) {
action.accept(t._1, t._2);
}
}
}