【问题标题】:Unmodifiable NavigableSet/NavigableMap in Java?Java中不可修改的NavigableSet/NavigableMap?
【发布时间】:2011-02-04 09:11:48
【问题描述】:

java.util.Collections 有几个 unmodifiable 方法,它们通过将集合包装在禁止突变操作的装饰器中来提供不可修改的集合视图。

Java 6 添加了对java.util.NavigableSet 和java.util.NavigableMap 的支持。

我希望能够拥有不可修改的NavigableSets 和NavigableMaps,但是java.util.Collections#unmodifiableSortedSet(SortedSet) 和java.util.Collections#unmodifiableSortedMap(SortedMap) 是不够的,因为它们不支持NavigableSet 和@ 特有的操作987654331@.

unmodifiableNavigableSet 和 unmodifiableNavigableMap 是否有事实上的实现?

【问题讨论】:

标签: java collections guava


【解决方案1】:

Guava 现在提供(自 2012 年 4 月 30 日发布的 12.0 版起)Maps.unmodifiableNavigableMap 和 Sets.unmodifiableNavigableSet。

【讨论】:

  • 请务必查看@JodaStephen 对 Java 8 的回答!
【解决方案2】:

Java SE 8 包含这两种方法。

请参阅Javadoc。

【讨论】:

    【解决方案3】:

    这只是一个猜测,但未提供不可修改实现的部分原因可能是 NavigableSet/Map 接口公开了未标记为可选的变异方法:

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

    也就是说,在提供不可修改的实现时仅抛出 UnsupportedOperationException 似乎是合理的。这就是在这些实现中所做的(假设您使用的是 GoogleGuava):

    可导航集:

    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));
        }
    }
    

    可导航地图:

    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));
        }
    }
    

    【讨论】:

    • 干得好!我不熟悉“com.amazon.agua.collections”。我意识到您只是在 Map 代码中引用 Set 代码,但是是否有一些公开可用的包可以维护这些东西?它将成为 JDK 的一个很好的补充。
    【解决方案4】:

    来自 Christian Semrau(在问题 cmets 中):

    JDK 中没有这样的方法,如this bug report 中所述。

    【讨论】:

      猜你喜欢
      • 2013-04-27
      • 1970-01-01
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 2017-10-15
      • 2016-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多