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

org.jhotdraw8.icollection.readonly.ReadOnlyMap Maven / Gradle / Ivy

The newest version!
/*
 * @(#)ReadOnlyMap.java
 * Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
 */
package org.jhotdraw8.icollection.readonly;

import org.jhotdraw8.icollection.facade.MapFacade;
import org.jhotdraw8.icollection.facade.ReadOnlyCollectionFacade;
import org.jhotdraw8.icollection.facade.ReadOnlySetFacade;
import org.jhotdraw8.icollection.impl.iteration.MappedIterator;
import org.jspecify.annotations.Nullable;

import java.util.AbstractMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;

/**
 * A read-only interface to a map. A map is an object that maps keys to values.
 *
 * @param  the key type
 * @param  the value type
 */
public interface ReadOnlyMap extends Iterable> {
    /**
     * Returns {@code true} if this map contains no entries.
     *
     * @return {@code true} if empty
     */
    boolean isEmpty();

    /**
     * Returns the number of entries contained in this map..
     *
     * @return the number of entries
     */
    int size();

    /**
     * Returns the value to which the key is mapped, or {@code null} if this map
     * contains no entry for the key.
     *
     * @param key a key
     * @return the mapped value or {@code null}
     */
    @Nullable V get(Object key);

    /**
     * Returns the value to which the key is mapped, or the specified default
     * value if this map contains no entry for the key.
     *
     * @param key          a key
     * @param defaultValue a default value
     * @return the mapped value or the specified default value
     */
    @SuppressWarnings("unchecked")
    default @Nullable V getOrDefault(Object key, @Nullable V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
                ? v
                : defaultValue;
    }

    /**
     * Returns {@code true} if this map contains a entry for the specified
     * key.
     *
     * @param key a key
     * @return {@code true} if this map contains a entry for the specified
     * key
     */
    boolean containsKey(@Nullable Object key);

    /**
     * Returns {@code true} if this map contains one or more keys to the
     * specified value.
     *
     * @param value a value
     * @return {@code true} if this map maps one or more keys to the
     * specified value
     */
    default boolean containsValue(@Nullable Object value) {
        for (Map.Entry entry : this) {
            if (Objects.equals(value, entry.getValue())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if this map contains the specified entry.
     *
     * @param o an entry (should be a {@link Map.Entry}).
     * @return true if this map contains the entry
     */
    default boolean containsEntry(Object o) {
        if (o instanceof Map.Entry) {
            @SuppressWarnings("unchecked") Map.Entry entry = (Map.Entry) o;
            return containsKey(entry.getKey())
                    && Objects.equals(entry.getValue(), get(entry.getKey()));
        }
        return false;
    }

    /**
     * Returns a {@link ReadOnlySet} view to the entries contained
     * in this map.
     *
     * @return a read-only view
     */
    default ReadOnlySet> readOnlyEntrySet() {
        return new ReadOnlySetFacade<>(
                this::iterator,
                this::size,
                this::containsEntry,
                Spliterator.NONNULL);
    }

    /**
     * Returns a {@link ReadOnlySet} view to the keys contained
     * in this map.
     *
     * @return a read-only view
     */
    default ReadOnlySet readOnlyKeySet() {
        return new ReadOnlySetFacade<>(
                () -> new MappedIterator<>(ReadOnlyMap.this.iterator(), Map.Entry::getKey),
                this::size,
                this::containsKey,
                0);
    }

    /**
     * Returns a {@link ReadOnlyCollection} view to the values contained
     * in this map.
     *
     * @return a read-only view
     */
    default ReadOnlyCollection readOnlyValues() {
        return new ReadOnlyCollectionFacade<>(
                () -> new MappedIterator<>(ReadOnlyMap.this.iterator(), Map.Entry::getValue),
                this::size,
                this::containsValue, characteristics()
        );
    }

    /**
     * Wraps this map in the {@link Map} interface - without copying.
     *
     * @return the wrapped map
     */
    default Map asMap() {
        return new MapFacade<>(this);
    }

    /**
     * Returns a string representation of the specified map.
     * 

* The string representation is consistent with the one produced * by {@link AbstractMap#toString()}. * * @param map a map * @param the key type * @param the value type * @return a string representation */ static String mapToString(final ReadOnlyMap map) { Iterator> i = map.iterator(); if (!i.hasNext()) { return "{}"; } StringBuilder sb = new StringBuilder(); sb.append('{'); for (; ; ) { Map.Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == map ? "(this Map)" : key); sb.append('='); sb.append(value == map ? "(this Map)" : value); if (!i.hasNext()) { return sb.append('}').toString(); } sb.append(',').append(' '); } } /** * Compares a read-only map with an object for equality. Returns * {@code true} if the given object is also a read-only map and the two maps * represent the same entries. * * @param map a map * @param o an object * @param the key type * @param the value type * @return {@code true} if the object is equal to the map */ static boolean mapEquals(ReadOnlyMap map, Object o) { if (o == map) { return true; } if (!(o instanceof ReadOnlyMap)) { return false; } @SuppressWarnings("unchecked") ReadOnlyMap that = (ReadOnlyMap) o; if (that.size() != map.size()) { return false; } try { for (Map.Entry e : map) { K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(that.get(key) == null && that.containsKey(key))) { return false; } } else { if (!value.equals(that.get(key))) { return false; } } } } catch (ClassCastException | NullPointerException unused) { return false; } return true; } /** * Returns the hash code of the provided iterable. The hash code * is the sum of the hash code of the entries. * * @param entries an iterable that is an entry set * @param the key type * @param the value type * @return the sum of the hash codes of the elements in the set * @see Map#hashCode() */ static int iteratorToHashCode(Iterator> entries) { return ReadOnlySet.iteratorToHashCode(entries); } /** * Compares the specified object with this map for equality. *

* Returns {@code true} if the given object is also a read-only map and the * two maps represent the same entries, ignorig the sequence of the * map entries. * * @param o an object * @return {@code true} if the object is equal to this map */ boolean equals(Object o); /** * Returns the hash code value for this map. The hash code * is the sum of the hash code of its entries. * * @return the hash code value for this map * @see Map#hashCode() */ int hashCode(); /** * Returns an iterator over the entries contained in this map. * * @return an iterator */ @Override Iterator> iterator(); /** * Returns a spliterator over the entries contained in this map. * * @return a spliterator */ @Override default Spliterator> spliterator() { //noinspection MagicConstant return Spliterators.spliterator(iterator(), size(), characteristics()); } /** * Returns the spliterator characteristics of the key set. *

* The default implementation in this interface * returns {@link Spliterator#SIZED}|{@link Spliterator#DISTINCT}. * * @return characteristics. */ default int characteristics() { return Spliterator.SIZED | Spliterator.DISTINCT; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy