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

io.vavr.collection.Map Maven / Gradle / Ivy

There is a newer version: 1.0.0-alpha-4
Show newest version
/*  __    __  __  __    __  ___
 * \  \  /  /    \  \  /  /  __/
 *  \  \/  /  /\  \  \/  /  /
 *   \____/__/  \__\____/__/
 *
 * Copyright 2014-2019 Vavr, http://vavr.io
 *
 * 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 io.vavr.collection;

import io.vavr.*;
import io.vavr.control.Option;

import java.io.Serializable;
import java.util.*;
import java.util.function.*;

/**
 * An immutable {@code Map} interface.
 *
 * 

* Basic operations: * *

    *
  • {@link #containsKey(Object)}
  • *
  • {@link #containsValue(Object)}
  • *
  • {@link #get(Object)}
  • *
  • {@link #keySet()}
  • *
  • {@link #merge(Map)}
  • *
  • {@link #merge(Map, BiFunction)}
  • *
  • {@link #put(Object, Object)}
  • *
  • {@link #put(Tuple2)}
  • *
  • {@link #put(Object, Object, BiFunction)}
  • *
  • {@link #put(Tuple2, BiFunction)}
  • *
  • {@link #values()}
  • *
* * Conversion: * *
    *
  • {@link #toJavaMap()}
  • *
* * Filtering: * *
    *
  • {@link #filter(BiPredicate)}
  • *
  • {@link #filterKeys(Predicate)}
  • *
  • {@link #filterValues(Predicate)}
  • *
  • {@link #reject(BiPredicate)}
  • *
  • {@link #rejectKeys(Predicate)}
  • *
  • {@link #rejectValues(Predicate)}
  • *
  • {@link #remove(Object)}
  • *
  • {@link #removeAll(Iterable)}
  • *
* * Iteration: * *
    *
  • {@link #forEach(BiConsumer)}
  • *
  • {@link #iterator(BiFunction)}
  • *
  • {@link #keysIterator()}
  • *
  • {@link #valuesIterator()}
  • *
* * Transformation: * *
    *
  • {@link #bimap(Function, Function)}
  • *
  • {@link #flatMap(BiFunction)}
  • *
  • {@link #lift()}
  • *
  • {@link #map(BiFunction)}
  • *
  • {@link #mapKeys(Function)}
  • *
  • {@link #mapKeys(Function, BiFunction)}
  • *
  • {@link #mapValues(Function)}
  • *
  • {@link #transform(Function)}
  • *
  • {@link #unzip(BiFunction)}
  • *
  • {@link #unzip3(BiFunction)}
  • *
  • {@link #withDefault(Function)}
  • *
  • {@link #withDefaultValue(Object)}
  • *
* * @param Key type * @param Value type * @author Daniel Dietrich, Ruslan Sennov */ public interface Map extends Traversable>, PartialFunction, Serializable { long serialVersionUID = 1L; /** * Narrows a widened {@code Map} 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 map) { return (Map) map; } /** * Convenience factory method to create a key/value pair. *

* If imported statically, this method allows to create a {@link Map} with arbitrary entries in a readable and * type-safe way, e.g.: *

     * {@code
     *
     * HashMap.ofEntries(
     *     entry(k1, v1),
     *     entry(k2, v2),
     *     entry(k3, v3)
     * );
     *
     * }
     * 
* * @param key the entry's key * @param value the entry's value * @param Key type * @param Value type * @return a key/value pair */ static Tuple2 entry(K key, V value) { return Tuple.of(key, value); } @Deprecated @Override default V apply(K key) { return get(key).getOrElseThrow(() -> new NoSuchElementException(String.valueOf(key))); } /** * Turns this {@code Map} into a {@link PartialFunction} which is defined at a specific index, if this {@code Map} * contains the given key. When applied to a defined key, the partial function will return * the value of this {@code Map} that is associated with the key. * * @return a new {@link PartialFunction} * @throws NoSuchElementException when a non-existing key is applied to the partial function */ default PartialFunction asPartialFunction() throws IndexOutOfBoundsException { return new PartialFunction() { private static final long serialVersionUID = 1L; @Override public V apply(K key) { return get(key).getOrElseThrow(() -> new NoSuchElementException(String.valueOf(key))); } @Override public boolean isDefinedAt(K key) { return containsKey(key); } }; } @Override default Seq collect(PartialFunction, ? extends R> partialFunction) { return io.vavr.collection.Vector.ofAll(iterator(). collect(partialFunction)); } /** * 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 keyMapper, Function valueMapper); @Override default boolean contains(Tuple2 element) { return get(element._1).map(v -> Objects.equals(v, element._2)).getOrElse(false); } /** * If the specified key is not already associated with a value, * attempts to compute its value using the given mapping * function and enters it into this map. * * @param key key whose presence in this map is to be tested * @param mappingFunction mapping function * @return the {@link Tuple2} of current or modified map and existing or computed value associated with the specified key */ Tuple2> computeIfAbsent(K key, Function mappingFunction); /** * If the value for the specified key is present, attempts to * compute a new mapping given the key and its current mapped value. * * @param key key whose presence in this map is to be tested * @param remappingFunction remapping function * @return the {@link Tuple2} of current or modified map and the {@code Some} of the value associated * with the specified key, or {@code None} if none */ Tuple2, ? extends Map> computeIfPresent(K key, BiFunction remappingFunction); /** * 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); } /** * Returns a new Map consisting of all elements which satisfy the given predicate. * * @param predicate the predicate used to test elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map filter(BiPredicate predicate); /** * Returns a new Map consisting of all elements which do not satisfy the given predicate. * * @param predicate the predicate used to test elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map reject(BiPredicate predicate); /** * Returns a new Map consisting of all elements with keys which satisfy the given predicate. * * @param predicate the predicate used to test keys of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map filterKeys(Predicate predicate); /** * Returns a new Map consisting of all elements with keys which do not satisfy the given predicate. * * @param predicate the predicate used to test keys of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map rejectKeys(Predicate predicate); /** * Returns a new Map consisting of all elements with values which satisfy the given predicate. * * @param predicate the predicate used to test values of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map filterValues(Predicate predicate); /** * Returns a new Map consisting of all elements with values which do not satisfy the given predicate. * * @param predicate the predicate used to test values of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ Map rejectValues(Predicate predicate); /** * 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>> mapper); /** * 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, ? extends Iterable> 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 U, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return iterator().foldRight(zero, f); } /** * 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); } } /** * 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 value associated with a key, or a default value if the key is not contained in the map. * * @param key the key * @param defaultValue a default value * @return the value associated with key if it exists, otherwise the default value. */ V getOrElse(K key, V defaultValue); @Override default boolean hasDefiniteSize() { return true; } @Override default boolean isTraversableAgain() { return true; } @Override Iterator> iterator(); /** * Iterates this Map sequentially, mapping the (key, value) pairs to elements. * * @param mapper A function that maps (key, value) pairs to elements of type U * @param The type of the resulting elements * @return An iterator through the mapped elements. */ default Iterator iterator(BiFunction mapper) { Objects.requireNonNull(mapper, "mapper is null"); return iterator().map(t -> mapper.apply(t._1, t._2)); } /** * Returns the keys contained in this map. * * @return {@code Set} of the keys contained in this map. */ io.vavr.collection.Set keySet(); /** * Returns the keys contained in this map as an iterator. * * @return {@code Iterator} of the keys contained in this map. */ default Iterator keysIterator() { return iterator().map(Tuple2::_1); } @Override default int length() { return size(); } /** * Turns this map into a plain function returning an Option result. * * @return a function that takes a key k and returns its value in a Some if found, otherwise a None. */ default Function1> lift() { return this::get; } /** * 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, ? 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(); } /** * 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> mapper); /** * Maps the keys of this {@code Map} while preserving the corresponding values. *

* The size of the result map may be smaller if {@code keyMapper} maps two or more distinct keys to the same new key. * In this case the value at the {@code latest} of the original keys is retained. * Order of keys is predictable in {@code TreeMap} (by comparator) and {@code LinkedHashMap} (insertion-order) and not predictable in {@code HashMap}. * * @param the new key type * @param keyMapper a {@code Function} that maps keys of type {@code V} to keys of type {@code V2} * @return a new {@code Map} * @throws NullPointerException if {@code keyMapper} is null */ Map mapKeys(Function keyMapper); /** * Maps the keys of this {@code Map} while preserving the corresponding values and applying a value merge function on collisions. *

* The size of the result map may be smaller if {@code keyMapper} maps two or more distinct keys to the same new key. * In this case the associated values will be combined using {@code valueMerge}. * * @param the new key type * @param keyMapper a {@code Function} that maps keys of type {@code V} to keys of type {@code V2} * @param valueMerge a {@code BiFunction} that merges values * @return a new {@code Map} * @throws NullPointerException if {@code keyMapper} is null */ Map mapKeys(Function keyMapper, BiFunction valueMerge); /** * 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 valueMapper); /** * 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 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 that, BiFunction collisionResolution); /** * 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 Tuple2 containing the key and value * @return A new Map containing these elements and that entry. */ Map put(Tuple2 entry); /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the merge * function is used to combine the previous value to the value to * be inserted, and the result of that call is inserted in the map. * * @param the value type * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @param merge function taking the old and new values and merging them. * @return A new Map containing these elements and that entry. */ Map put(K key, U value, BiFunction merge); /** * Convenience method for {@code put(entry._1, entry._2, merge)}. * * @param the value type * @param entry A Tuple2 containing the key and value * @param merge function taking the old and new values and merging them. * @return A new Map containing these elements and that entry. */ Map put(Tuple2 entry, BiFunction merge); /** * 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); /** * Returns a new Map consisting of all elements which do not satisfy the given predicate. * * @deprecated Please use {@link #reject(BiPredicate)} * @param predicate the predicate used to test elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ @Deprecated Map removeAll(BiPredicate predicate); /** * 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 keys); /** * Returns a new Map consisting of all elements with keys which do not satisfy the given predicate. * * @deprecated Please use {@link #rejectKeys(Predicate)} * @param predicate the predicate used to test keys of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ @Deprecated Map removeKeys(Predicate predicate); /** * Returns a new Map consisting of all elements with values which do not satisfy the given predicate. * * @deprecated Please use {@link #rejectValues(Predicate)} * @param predicate the predicate used to test values of elements * @return a new Map * @throws NullPointerException if {@code predicate} is null */ @Deprecated Map removeValues(Predicate predicate); @Override default Seq scanLeft(U zero, BiFunction, ? extends U> operation) { return io.vavr.collection.Collections.scanLeft(this, zero, operation, io.vavr.collection.Iterator::toVector); } @Override default Seq scanRight(U zero, BiFunction, ? super U, ? extends U> operation) { return io.vavr.collection.Collections.scanRight(this, zero, operation, io.vavr.collection.Iterator::toVector); } @Override int size(); /** * Converts this Vavr {@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, ? extends U> f) { Objects.requireNonNull(f, "f is null"); return f.apply(this); } default Tuple2, Seq> unzip() { return unzip(Function.identity()); } default Tuple2, Seq> unzip(BiFunction> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return unzip(entry -> unzipper.apply(entry._1, entry._2)); } @Override default Tuple2, Seq> unzip(Function, Tuple2> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip(unzipper).map(Stream::ofAll, Stream::ofAll); } default Tuple3, Seq, Seq> unzip3(BiFunction> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return unzip3(entry -> unzipper.apply(entry._1, entry._2)); } @Override default Tuple3, Seq, Seq> unzip3( Function, Tuple3> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip3(unzipper).map(Stream::ofAll, Stream::ofAll, Stream::ofAll); } /** * Returns a new {@link Seq} that contains the values of this {@code Map}. * *

{@code
     * // = Seq("a", "b", "c")
     * HashMap.of(1, "a", 2, "b", 3, "c").values()
     * }
* * @return a new {@link Seq} */ Seq values(); /** * Returns the values in this map. * *
{@code
     * // = Iterator.of("a", "b", "c")
     * HashMap.of(1, "a", 2, "b", 3, "c").values()
     * }
* * @return a new {@link Iterator} */ default Iterator valuesIterator() { return iterator().map(Tuple2::_2); } /** * Turns this map from a partial function into a total function that * returns a value computed by defaultFunction for all keys * absent from the map. * * @param defaultFunction function to evaluate for all keys not present in the map * @return a total function from K to T * @deprecated Will be removed */ @Deprecated default Function1 withDefault(Function defaultFunction) { return k -> get(k).getOrElse(() -> defaultFunction.apply(k)); } /** * Turns this map from a partial function into a total function that * returns defaultValue for all keys absent from the map. * * @param defaultValue default value to return for all keys not present in the map * @return a total function from K to T * @deprecated Will be removed */ @Deprecated default Function1 withDefaultValue(V defaultValue) { return k -> get(k).getOrElse(defaultValue); } @Override default Seq, U>> zip(Iterable that) { return zipWith(that, Tuple::of); } @Override default Seq zipWith(Iterable that, BiFunction, ? super U, ? extends R> mapper) { Objects.requireNonNull(that, "that is null"); Objects.requireNonNull(mapper, "mapper is null"); return Stream.ofAll(iterator().zipWith(that, mapper)); } @Override default Seq, U>> zipAll(Iterable that, Tuple2 thisElem, U thatElem) { Objects.requireNonNull(that, "that is null"); return Stream.ofAll(iterator().zipAll(that, thisElem, thatElem)); } @Override default Seq, Integer>> zipWithIndex() { return zipWithIndex(Tuple::of); } @Override default Seq zipWithIndex(BiFunction, ? super Integer, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return Stream.ofAll(iterator().zipWithIndex(mapper)); } // -- Adjusted return types of Traversable methods @Override Map distinct(); @Override Map distinctBy(Comparator> comparator); @Override Map distinctBy(Function, ? extends U> keyExtractor); @Override Map drop(int n); @Override Map dropRight(int n); @Override Map dropUntil(Predicate> predicate); @Override Map dropWhile(Predicate> predicate); @Override Map filter(Predicate> predicate); @Override Map reject(Predicate> predicate); @Override Map> groupBy(Function, ? extends C> classifier); @Override io.vavr.collection.Iterator> grouped(int size); @Deprecated @Override default boolean isDefinedAt(K key) { return containsKey(key); } @Override default boolean isDistinct() { return true; } @Override Map init(); @Override Option> initOption(); @Override Map orElse(Iterable> other); @Override Map orElse(Supplier>> supplier); @Override Tuple2, ? extends Map> partition(Predicate> predicate); @Override Map peek(Consumer> action); @Override Map replace(Tuple2 currentElement, Tuple2 newElement); /** * Replaces the entry for the specified key only if it is currently mapped to some value. * * @param key the key of the element to be substituted. * @param value the new value to be associated with the key * @return a new map containing key mapped to value if key was contained before. The old map otherwise. */ Map replaceValue(K key, V value); /** * Replaces the entry for the specified key only if currently mapped to the specified value. * * @param key the key of the element to be substituted. * @param oldValue the expected current value that the key is currently mapped to * @param newValue the new value to be associated with the key * @return a new map containing key mapped to newValue if key was contained before and oldValue matched. The old map otherwise. */ Map replace(K key, V oldValue, V newValue); /** * Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception. * * @param function function transforming key and current value to a new value * @return a new map with the same keySet but transformed values. */ Map replaceAll(BiFunction function); @Override Map replaceAll(Tuple2 currentElement, Tuple2 newElement); @Override Map retainAll(Iterable> elements); @Override Map scan(Tuple2 zero, BiFunction, ? super Tuple2, ? extends Tuple2> operation); @Override io.vavr.collection.Iterator> slideBy(Function, ?> classifier); @Override io.vavr.collection.Iterator> sliding(int size); @Override io.vavr.collection.Iterator> sliding(int size, int step); @Override Tuple2, ? extends Map> span(Predicate> predicate); @Override Map tail(); @Override Option> tailOption(); @Override Map take(int n); @Override Map takeRight(int n); @Override Map takeUntil(Predicate> predicate); @Override Map takeWhile(Predicate> predicate); }