/*
 * Copyright (c) 2018 Goldman Sachs.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v. 1.0 which accompany this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */

package org.eclipse.collections.api.map;

import java.util.Map;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.eclipse.collections.api.RichIterable;
import org.eclipse.collections.api.block.function.Function;
import org.eclipse.collections.api.block.function.Function0;
import org.eclipse.collections.api.block.function.Function2;
import org.eclipse.collections.api.block.predicate.Predicate2;
import org.eclipse.collections.api.block.procedure.Procedure;
import org.eclipse.collections.api.block.procedure.Procedure2;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.multimap.Multimap;
import org.eclipse.collections.api.tuple.Pair;

A Read-only Map API, with the minor exception inherited from java.lang.Iterable. The method map.iterator().remove() will throw an UnsupportedOperationException.
/** * A Read-only Map API, with the minor exception inherited from java.lang.Iterable. The method map.iterator().remove() * will throw an UnsupportedOperationException. */
public interface MapIterable<K, V> extends RichIterable<V> {
See Also:
  • get.get(Object)
/** * @see Map#get(Object) */
V get(Object key);
See Also:
  • containsKey.containsKey(Object)
/** * @see Map#containsKey(Object) */
boolean containsKey(Object key);
See Also:
  • containsValue.containsValue(Object)
/** * @see Map#containsValue(Object) */
boolean containsValue(Object value);
Calls the procedure with each value of the map.
    Set<String> result = UnifiedSet.newSet();
    MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four");
    map.forEachValue(new CollectionAddProcedure<String>(result));
    Verify.assertSetsEqual(UnifiedSet.newSetWith("One", "Two", "Three", "Four"), result);
/** * Calls the procedure with each <em>value</em> of the map. * <pre> * Set&lt;String&gt; result = UnifiedSet.newSet(); * MutableMap&lt;Integer, String&gt; map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three", 4, "Four"); * map.<b>forEachValue</b>(new CollectionAddProcedure&lt;String&gt;(result)); * Verify.assertSetsEqual(UnifiedSet.newSetWith("One", "Two", "Three", "Four"), result); * </pre> */
void forEachValue(Procedure<? super V> procedure);
Executes the Procedure for each value of the map and returns this.
return peopleByCity.tap(person -> LOGGER.info(person.getName()));
See Also:
Since:6.0
/** * Executes the Procedure for each value of the map and returns {@code this}. * * <pre> * return peopleByCity.<b>tap</b>(person -&gt; LOGGER.info(person.getName())); * </pre> * * @see #forEach(Procedure) * @since 6.0 */
@Override MapIterable<K, V> tap(Procedure<? super V> procedure);
Calls the procedure with each key of the map.
    final Collection<Integer> result = new ArrayList<Integer>();
    MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3");
    map.forEachKey(new CollectionAddProcedure<Integer>(result));
    Verify.assertContainsAll(result, 1, 2, 3);
/** * Calls the {@code procedure} with each <em>key</em> of the map. * <pre> * final Collection&lt;Integer&gt; result = new ArrayList&lt;Integer&gt;(); * MutableMap&lt;Integer, String&gt; map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3"); * map.<b>forEachKey</b>(new CollectionAddProcedure&lt;Integer&gt;(result)); * Verify.assertContainsAll(result, 1, 2, 3); * </pre> */
void forEachKey(Procedure<? super K> procedure);
Calls the procedure with each key-value pair of the map.
    final Collection<String> collection = new ArrayList<String>();
    MutableMap<Integer, String> map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three");
    map.forEachKeyValue((Integer key, String value) -> collection.add(String.valueOf(key) + value));
    Verify.assertContainsAll(collection, "1One", "2Two", "3Three");
/** * Calls the {@code procedure} with each <em>key-value</em> pair of the map. * <pre> * final Collection&lt;String&gt; collection = new ArrayList&lt;String&gt;(); * MutableMap&lt;Integer, String&gt; map = this.newMapWithKeysValues(1, "One", 2, "Two", 3, "Three"); * map.<b>forEachKeyValue</b>((Integer key, String value) -&gt; collection.add(String.valueOf(key) + value)); * Verify.assertContainsAll(collection, "1One", "2Two", "3Three"); * </pre> */
void forEachKeyValue(Procedure2<? super K, ? super V> procedure);
Return the MapIterable that is obtained by flipping the direction of this map and making the associations from value to key.
    MapIterable<Integer, String> map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3");
    MapIterable<String, Integer> result = map.flipUniqueValues();
    Assert.assertTrue(result.equals(UnifiedMap.newWithKeysValues("1", 1, "2", 2, "3", 3)));
Throws:
  • IllegalStateException – if the MapIterable contains duplicate values.
Since:5.0
/** * Return the MapIterable that is obtained by flipping the direction of this map and making the associations * from value to key. * <pre> * MapIterable&lt;Integer, String&gt; map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3"); * MapIterable&lt;String, Integer&gt; result = map.flipUniqueValues(); * Assert.assertTrue(result.equals(UnifiedMap.newWithKeysValues("1", 1, "2", 2, "3", 3))); * </pre> * * @throws IllegalStateException if the MapIterable contains duplicate values. * @since 5.0 */
MapIterable<V, K> flipUniqueValues(); default V getOrDefault(Object key, V defaultValue) { return this.getIfAbsentValue((K) key, defaultValue); }
Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the result of evaluating the specified Function0.
/** * Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the * result of evaluating the specified Function0. */
V getIfAbsent(K key, Function0<? extends V> function);
Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return value.
/** * Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return {@code value}. */
V getIfAbsentValue(K key, V value);
Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the result of evaluating the specified function and parameter.
/** * Return the value in the Map that corresponds to the specified key, or if there is no value at the key, return the * result of evaluating the specified function and parameter. */
<P> V getIfAbsentWith(K key, Function<? super P, ? extends V> function, P parameter);
If there is a value in the Map that corresponds to the specified key return the result of applying the specified Function on the value, otherwise return null.
/** * If there is a value in the Map that corresponds to the specified key return the result of applying the specified * Function on the value, otherwise return null. */
<A> A ifPresentApply(K key, Function<? super V, ? extends A> function);
Returns an unmodifiable lazy iterable wrapped around the keySet for the map.
/** * Returns an unmodifiable lazy iterable wrapped around the keySet for the map. */
RichIterable<K> keysView();
Returns an unmodifiable lazy iterable wrapped around the values for the map.
/** * Returns an unmodifiable lazy iterable wrapped around the values for the map. */
RichIterable<V> valuesView();
Returns an unmodifiable lazy iterable of key/value pairs wrapped around the entrySet for the map.
/** * Returns an unmodifiable lazy iterable of key/value pairs wrapped around the entrySet for the map. */
RichIterable<Pair<K, V>> keyValuesView();
Given a map from Domain -> Range return a multimap from Range -> Domain. We chose the name 'flip' rather than 'invert' or 'transpose' since this method does not have the property of applying twice returns the original.

Since the keys in the input are unique, the values in the output are unique, so the return type should be a SetMultimap. However since SetMultimap and SortedSetMultimap don't inherit from one another, SetMultimap here does not allow SortedMapIterable to have a SortedSetMultimap return. Thus we compromise and call this Multimap, even though all implementations will be a SetMultimap or SortedSetMultimap.

Since:5.0
/** * Given a map from Domain {@code ->} Range return a multimap from Range {@code ->} Domain. We chose the name 'flip' * rather than 'invert' or 'transpose' since this method does not have the property of applying twice * returns the original. * <p> * Since the keys in the input are unique, the values in the output are unique, so the return type should * be a SetMultimap. However since SetMultimap and SortedSetMultimap don't inherit from one another, SetMultimap * here does not allow SortedMapIterable to have a SortedSetMultimap return. Thus we compromise and call this * Multimap, even though all implementations will be a SetMultimap or SortedSetMultimap. * * @since 5.0 */
Multimap<V, K> flip();
For each key and value of the map the predicate is evaluated, if the result of the evaluation is true, that key and value are returned in a new map.
MapIterable<City, Person> selected =
    peopleByCity.select((city, person) -> city.getName().equals("Anytown") && person.getLastName().equals("Smith"));
/** * For each key and value of the map the predicate is evaluated, if the result of the evaluation is true, * that key and value are returned in a new map. * * <pre> * MapIterable&lt;City, Person&gt; selected = * peopleByCity.select((city, person) -&gt; city.getName().equals("Anytown") &amp;&amp; person.getLastName().equals("Smith")); * </pre> */
MapIterable<K, V> select(Predicate2<? super K, ? super V> predicate);
For each key and value of the map the predicate is evaluated, if the result of the evaluation is false, that key and value are returned in a new map.
MapIterable<City, Person> rejected =
    peopleByCity.reject((city, person) -> city.getName().equals("Anytown") && person.getLastName().equals("Smith"));
/** * For each key and value of the map the predicate is evaluated, if the result of the evaluation is false, * that key and value are returned in a new map. * * <pre> * MapIterable&lt;City, Person&gt; rejected = * peopleByCity.reject((city, person) -&gt; city.getName().equals("Anytown") &amp;&amp; person.getLastName().equals("Smith")); * </pre> */
MapIterable<K, V> reject(Predicate2<? super K, ? super V> predicate);
For each key and value of the map the function is evaluated. The results of these evaluations are returned in a new map. The map returned will use the values projected from the function rather than the original values.
MapIterable<String, String> collected =
    peopleByCity.collect((City city, Person person) -> Pair.of(city.getCountry(), person.getAddress().getCity()));
/** * For each key and value of the map the function is evaluated. The results of these evaluations are returned in * a new map. The map returned will use the values projected from the function rather than the original values. * * <pre> * MapIterable&lt;String, String&gt; collected = * peopleByCity.collect((City city, Person person) -&gt; Pair.of(city.getCountry(), person.getAddress().getCity())); * </pre> */
<K2, V2> MapIterable<K2, V2> collect(Function2<? super K, ? super V, Pair<K2, V2>> function);
For each key and value of the map the function is evaluated. The results of these evaluations are returned in a new map. The map returned will use the values projected from the function rather than the original values.
MapIterable<City, String> collected =
    peopleByCity.collectValues((City city, Person person) -> person.getFirstName() + " " + person.getLastName());
/** * For each key and value of the map the function is evaluated. The results of these evaluations are returned in * a new map. The map returned will use the values projected from the function rather than the original values. * * <pre> * MapIterable&lt;City, String&gt; collected = * peopleByCity.collectValues((City city, Person person) -&gt; person.getFirstName() + " " + person.getLastName()); * </pre> */
<R> MapIterable<K, R> collectValues(Function2<? super K, ? super V, ? extends R> function);
Return the first key and value of the map for which the predicate evaluates to true when they are given as arguments. The predicate will only be evaluated until such pair is found or until all of the keys and values of the map have been used as arguments. That is, there may be keys and values of the map that are never used as arguments to the predicate. The result is null if predicate does not evaluate to true for any key/value combination.
Pair<City, Person> detected =
    peopleByCity.detect((City city, Person person) -> city.getName().equals("Anytown") && person.getLastName().equals("Smith"));
/** * Return the first key and value of the map for which the predicate evaluates to true when they are given * as arguments. The predicate will only be evaluated until such pair is found or until all of the keys and * values of the map have been used as arguments. That is, there may be keys and values of the map that are * never used as arguments to the predicate. The result is null if predicate does not evaluate to true for * any key/value combination. * * <pre> * Pair&lt;City, Person&gt; detected = * peopleByCity.detect((City city, Person person) -&gt; city.getName().equals("Anytown") &amp;&amp; person.getLastName().equals("Smith")); * </pre> */
Pair<K, V> detect(Predicate2<? super K, ? super V> predicate);
Return the first key and value of the map as an Optional for which the predicate evaluates to true when they are given as arguments. The predicate will only be evaluated until such pair is found or until all of the keys and values of the map have been used as arguments. That is, there may be keys and values of the map that are never used as arguments to the predicate.
Optional<Pair<City, Person>> detected =
    peopleByCity.detectOptional((city, person)
         -> city.getName().equals("Anytown") && person.getLastName().equals("Smith"));
/** * Return the first key and value of the map as an Optional for which the predicate evaluates to true when * they are given as arguments. The predicate will only be evaluated until such pair is found or until all * of the keys and values of the map have been used as arguments. That is, there may be keys and values of * the map that are never used as arguments to the predicate. * * <pre> * Optional&lt;Pair&lt;City, Person&gt;&gt; detected = * peopleByCity.detectOptional((city, person) * -&gt; city.getName().equals("Anytown") &amp;&amp; person.getLastName().equals("Smith")); * </pre> */
Optional<Pair<K, V>> detectOptional(Predicate2<? super K, ? super V> predicate);
Follows the same general contract as Map.equals(Object).
/** * Follows the same general contract as {@link Map#equals(Object)}. */
@Override boolean equals(Object o);
Follows the same general contract as Map.hashCode().
/** * Follows the same general contract as {@link Map#hashCode()}. */
@Override int hashCode();
Returns a string with the keys and values of this map separated by commas with spaces and enclosed in curly braces. Each key and value is separated by an equals sign.
Assert.assertEquals("{1=1, 2=2, 3=3}", Maps.mutable.with(1, 1, 2, 2, 3, 3).toString());
See Also:
Returns:a string representation of this MapIterable
/** * Returns a string with the keys and values of this map separated by commas with spaces and * enclosed in curly braces. Each key and value is separated by an equals sign. * * <pre> * Assert.assertEquals("{1=1, 2=2, 3=3}", Maps.mutable.with(1, 1, 2, 2, 3, 3).toString()); * </pre> * * @return a string representation of this MapIterable * @see java.util.AbstractMap#toString() */
@Override String toString(); ImmutableMapIterable<K, V> toImmutable();
Since:9.0
/** * @since 9.0 */
default Stream<V> stream() { return StreamSupport.stream(this.spliterator(), false); }
Since:9.0
/** * @since 9.0 */
default Stream<V> parallelStream() { return StreamSupport.stream(this.spliterator(), true); }
Since:9.0
/** * @since 9.0 */
@Override default Spliterator<V> spliterator() { return Spliterators.spliterator(this.iterator(), (long) this.size(), 0); }
Applies an aggregate function over the map grouping results into a map based on the specific key and value groupBy functions. Aggregate results are allowed to be immutable as they will be replaced in place in the map. A second function specifies the initial "zero" aggregate value to work with.
MapIterable<String, Interval> map = Maps.mutable.with("oneToFive", Interval.fromTo(1, 5), "sixToNine", Interval.fromTo(6, 9));
MapIterable<String, Long> result = map.aggregateBy(
        eachKey -> {
            return eachKey.equals("oneToFive")  ? "lessThanSix" : "greaterOrEqualsToSix";
        },
        each -> each.sumOfInt(Integer::intValue),
        () -> 0L,
        (argument1, argument2) -> argument1 + argument2);
MapIterable<String, Long> expected =
        Maps.mutable.with("lessThanSix", Interval.fromTo(1, 5).sumOfInt(Integer::intValue),
                "greaterOrEqualsToSix", Interval.fromTo(6, 9).sumOfInt(Integer::intValue));
Assert.assertEquals(expected, result);
Since:10.3.0
/** * Applies an aggregate function over the map grouping results into a map based on the specific key and value groupBy functions. * Aggregate results are allowed to be immutable as they will be replaced in place in the map. A second function * specifies the initial "zero" aggregate value to work with. * * <pre> * MapIterable&lt;String, Interval&gt; map = Maps.mutable.with("oneToFive", Interval.fromTo(1, 5), "sixToNine", Interval.fromTo(6, 9)); * * MapIterable&lt;String, Long&gt; result = map.aggregateBy( * eachKey -&gt; { * return eachKey.equals("oneToFive") ? "lessThanSix" : "greaterOrEqualsToSix"; * }, * each -&gt; each.sumOfInt(Integer::intValue), * () -&gt; 0L, * (argument1, argument2) -&gt; argument1 + argument2); * * MapIterable&lt;String, Long&gt; expected = * Maps.mutable.with("lessThanSix", Interval.fromTo(1, 5).sumOfInt(Integer::intValue), * "greaterOrEqualsToSix", Interval.fromTo(6, 9).sumOfInt(Integer::intValue)); * Assert.assertEquals(expected, result); * </pre> * * @since 10.3.0 */
default <K1, V1, V2> MapIterable<K1, V2> aggregateBy( Function<? super K, ? extends K1> keyFunction, Function<? super V, ? extends V1> valueFunction, Function0<? extends V2> zeroValueFactory, Function2<? super V2, ? super V1, ? extends V2> nonMutatingAggregator) { MutableMap<K1, V2> map = Maps.mutable.empty(); this.forEachKeyValue((key, value) -> { map.updateValueWith( keyFunction.valueOf(key), zeroValueFactory, nonMutatingAggregator, valueFunction.valueOf(value)); }); return map; } }