开发者

Unmodifiable NavigableSet/NavigableMap in Java?

开发者 https://www.devze.com 2022-12-25 21:43 出处:网络
java.util.Collections has several unmodifiable methods that provide unmodifiable collection views by wrapping collections in decorators that prohibit mutation operations.

java.util.Collections has several unmodifiable methods that provide unmodifiable collection views by wrapping collections in decorators that prohibit mutation operations.

Java 6 added support for java.util.NavigableSet and java.util.NavigableMap.

I'd like to be able to have unmodifiable NavigableSets and NavigableMaps, but java.util.Collections#unmodifiableSortedSet(SortedSet) and java.util.Collections#unmodifiableSortedMap(SortedMap) are not sufficient because they do not support the operations that are particular to NavigableSet and NavigableMap.

Are there de-facto implementations开发者_JAVA百科 for unmodifiableNavigableSet and unmodifiableNavigableMap?


Guava now provides (since version 12.0, released April 30, 2012) Maps.unmodifiableNavigableMap and Sets.unmodifiableNavigableSet.


Java SE 8 included these two methods.

See the Javadoc.


This is just a guess, but part of the reason why an unmodifiable implementation was not provided may be due to the fact that the NavigableSet/Map interfaces expose mutating methods that aren't marked as optional:

  • NavigableSet.pollFirst
  • NavigableSet.pollLast
  • NavigableMap.pollFirstEntry
  • NavigableMap.pollLastEntry

That said, it seems reasonable when providing an unmodifiable implementation to just throw an UnsupportedOperationException. That is what is done in these implementations (which assume you're using GoogleGuava):

NavigableSet:

import static java.util.Collections.unmodifiableSortedSet;

import java.util.Collections;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.SortedSet;

import com.google.common.collect.ForwardingSortedSet;

/**
 * {@link NavigableSet} equivalent of {@link Collections#unmodifiableSortedSet(SortedSet)}.
 * This is unfortunately needed because {@link Collections} lacks "UnmodifiableNavigableSet"
 * (see http://stackoverflow.com/questions/2577706/unmodifiable-navigableset-navigablemap-in-java
 * and http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6907251).
 * 
 * This is just a guess, but part of the reason why an unmodifiable implementation was not provided may be due to the fact that 
 * {@link NavigableSet} exposes mutating methods that aren't marked as optional:
 * - {@link NavigableSet#pollFirst()}
 * - {@link NavigableSet#pollLast()}
 *  
 * In addition, one can't go the immutable route, as Google Guava doesn't provide an Immutable variant 
 * (see http://code.google.com/p/guava-libraries/issues/detail?id=664).
 *
 * @param <E> See {@link NavigableSet}
 */
public final class UnmodifiableNavigableSet<E> extends ForwardingSortedSet<E> implements NavigableSet<E> {

    private final NavigableSet<E> delegate;
    private final SortedSet<E> unmodifiableDelegate;

    /**
     * @param delegate See {@link ForwardingSortedSet#delegate()}.
     */
    public UnmodifiableNavigableSet(NavigableSet<E> delegate) {
        this.delegate = delegate;
        unmodifiableDelegate = unmodifiableSortedSet(delegate);
    }

    /**
     * @param delegate
     * @return {@link #UnmodifiableNavigableSet(NavigableSet)}
     * @see EffectiveJava#Static_factories_instead_of_constructors
     */
    public static <E> UnmodifiableNavigableSet<E> newUnmodifiableNavigableSet(NavigableSet<E> delegate) {
        return new UnmodifiableNavigableSet<E>(delegate);
    }

    @Override
    protected SortedSet<E> delegate() {
        return unmodifiableDelegate;
    }

    @Override
    public E ceiling(E e) {
        return delegate.ceiling(e);
    }

    @Override
    public Iterator<E> descendingIterator() {
        // NavigableSet.descendingIterator explicitly states this behavior.
        // By doing this, we don't need to do anything extra to ensure the iterator is unmodifiable.
        return descendingSet().iterator();
    }

    @Override
    public NavigableSet<E> descendingSet() {
        return newUnmodifiableNavigableSet(delegate.descendingSet());
    }

    @Override
    public E floor(E e) {
        return delegate.floor(e);
    }

    @Override
    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
        return newUnmodifiableNavigableSet(delegate.headSet(toElement, inclusive));
    }

    @Override
    public E higher(E e) {
        return delegate.higher(e);
    }

    @Override
    public E lower(E e) {
        return delegate.lower(e);
    }

    @Override
    public E pollFirst() {
        throw new UnsupportedOperationException();
    }

    @Override
    public E pollLast() {
        throw new UnsupportedOperationException();
    }

    @Override
    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
        return newUnmodifiableNavigableSet(delegate.subSet(fromElement, fromInclusive, toElement, toInclusive));
    }

    @Override
    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
        return newUnmodifiableNavigableSet(delegate.tailSet(fromElement, inclusive));
    }
}

NavigableMap:

import static UnmodifiableNavigableSet.newUnmodifiableNavigableSet;
import static java.util.Collections.unmodifiableSortedMap;

import java.util.AbstractMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.SortedMap;

import com.google.common.collect.ForwardingSortedMap;

/**
 * This class has the same rational as {@link UnmodifiableNavigableSet}.
 * @param <K> See {@link NavigableMap}
 * @param <V> See {@link NavigableMap}
 */
public final class UnmodifiableNavigableMap<K,V> extends ForwardingSortedMap<K,V> implements NavigableMap<K,V> {

    private final NavigableMap<K,V> delegate;
    private final SortedMap<K,V> unmodifiableDelegate;

    /**
     * @param delegate See {@link ForwardingSortedMap#delegate()}.
     */
    public UnmodifiableNavigableMap(NavigableMap<K,V> delegate) {
        this.delegate = delegate;
        unmodifiableDelegate = unmodifiableSortedMap(delegate);
    }

    /**
     * @param delegate
     * @return {@link #UnmodifiableNavigableMap(NavigableMap)}
     * @see EffectiveJava#Static_factories_instead_of_constructors
     */
    public static <K,V> UnmodifiableNavigableMap<K,V> newUnmodifiableNavigableMap(NavigableMap<K,V> delegate) {
        return new UnmodifiableNavigableMap<K,V>(delegate);
    }

    @Override
    protected SortedMap<K,V> delegate() {
        return unmodifiableDelegate;
    }

    private Map.Entry<K,V> newImmutableEntry(Map.Entry<K,V> entry) {
        return entry == null ? null : new AbstractMap.SimpleImmutableEntry<K,V>(entry);
    }

    @Override
    public Map.Entry<K,V> ceilingEntry(K key) {
        return newImmutableEntry(delegate.ceilingEntry(key));
    }

    @Override
    public K ceilingKey(K key) {
        return delegate.ceilingKey(key);
    }

    @Override
    public NavigableSet<K> descendingKeySet() {
        return newUnmodifiableNavigableSet(delegate.descendingKeySet());
    }

    @Override
    public NavigableMap<K,V> descendingMap() {
        return newUnmodifiableNavigableMap(delegate.descendingMap());
    }

    @Override
    public Map.Entry<K,V> firstEntry() {
        return newImmutableEntry(delegate.firstEntry());
    }

    @Override
    public Map.Entry<K,V> floorEntry(K key) {
        return newImmutableEntry(delegate.floorEntry(key));
    }

    @Override
    public K floorKey(K key) {
        return delegate.floorKey(key);
    }

    @Override
    public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
        return newUnmodifiableNavigableMap(delegate.headMap(toKey, inclusive));
    }

    @Override
    public Map.Entry<K,V> higherEntry(K key) {
        return newImmutableEntry(delegate.higherEntry(key));
    }

    @Override
    public K higherKey(K key) {
        return delegate.higherKey(key);
    }

    @Override
    public Map.Entry<K,V> lastEntry() {
        return newImmutableEntry(delegate.lastEntry());
    }

    @Override
    public Map.Entry<K,V> lowerEntry(K key) {
        return newImmutableEntry(delegate.lowerEntry(key));
    }

    @Override
    public K lowerKey(K key) {
        return delegate.lowerKey(key);
    }

    @Override
    public NavigableSet<K> navigableKeySet() {
        return newUnmodifiableNavigableSet(delegate.navigableKeySet());
    }

    @Override
    public Map.Entry<K,V> pollFirstEntry() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Map.Entry<K,V> pollLastEntry() {
        throw new UnsupportedOperationException();
    }

    @Override
    public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
        return newUnmodifiableNavigableMap(delegate.subMap(fromKey, fromInclusive, toKey, toInclusive));
    }

    @Override
    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
        return newUnmodifiableNavigableMap(delegate.tailMap(fromKey, inclusive));
    }
}


From Christian Semrau (in the question comments):

There are no such methods within the JDK, as mentioned in this bug report.

0

精彩评论

暂无评论...
验证码 换一张
取 消