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

javaslang.collection.Map Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   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} 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;
    }

    @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 keyMapper, Function 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>> 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> 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 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 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 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, ? 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> unzipper) {
        Objects.requireNonNull(unzipper, "unzipper is null");
        return unzip(entry -> unzipper.apply(entry._1, entry._2));
    }

    default  Tuple3, Seq, Seq> unzip3(BiFunction> 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> comparator);

    @Override
     Map distinctBy(Function, ? extends U> keyExtractor);

    @Override
    Map drop(long n);

    @Override
    Map dropRight(long n);

    @Override
    Map dropUntil(Predicate> predicate);

    @Override
    Map dropWhile(Predicate> predicate);

    @Override
    Map filter(Predicate> 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, ? 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); } @Override Map> groupBy(Function, ? extends C> classifier); @Override Iterator> grouped(long size); @Override default boolean hasDefiniteSize() { return true; } @Override Map init(); @Override Option> 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, ? 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 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); @Override Tuple2, ? extends Map> partition(Predicate> predicate); @Override Map peek(Consumer> action); @Override Map replace(Tuple2 currentElement, Tuple2 newElement); @Override Map replaceAll(Tuple2 currentElement, Tuple2 newElement); @Override Map retainAll(Iterable> elements); @Override Map scan(Tuple2 zero, BiFunction, ? super Tuple2, ? extends Tuple2> operation); @Override default Seq scanLeft(U zero, BiFunction, ? 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 U, ? extends U> operation) { Objects.requireNonNull(operation, "operation is null"); return Collections.scanRight(this, zero, operation, List.empty(), List::prepend, Function.identity()); } @Override Iterator> sliding(long size); @Override Iterator> sliding(long size, long step); @Override Tuple2, ? extends Map> span(Predicate> predicate); @Override default Spliterator> spliterator() { return Spliterators.spliterator(iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE); } @Override Map tail(); @Override Option> tailOption(); @Override Map take(long n); @Override Map takeRight(long n); @Override Map takeUntil(Predicate> predicate); @Override Map takeWhile(Predicate> predicate); @Override default Tuple2, Seq> unzip(Function, Tuple2> unzipper) { Objects.requireNonNull(unzipper, "unzipper is null"); return iterator().unzip(unzipper).map(Stream::ofAll, Stream::ofAll); } @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); } @Override default Seq, U>> zip(Iterable that) { Objects.requireNonNull(that, "that is null"); return Stream.ofAll(iterator().zip(that)); } @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, 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); } } }