2010-04-05 4 views
13

java.util.Collections tiene varios métodos unmodifiable que proporcionan vistas de colección no modificables envolviendo colecciones en decoradores que prohíben las operaciones de mutación.NavigableSet/NavigableMap inmodificable en Java?

Java 6 agregó soporte para java.util.NavigableSet y java.util.NavigableMap.

me gustaría ser capaz de tener inmodificable NavigableSet s y NavigableMap s, pero java.util.Collections#unmodifiableSortedSet(SortedSet) y java.util.Collections#unmodifiableSortedMap(SortedMap) no son suficientes, ya que no son compatibles con las operaciones que son particulares a NavigableSet y NavigableMap.

¿Existen implementaciones de facto para unmodifiableNavigableSet y unmodifiableNavigableMap?

+0

Oops ... parece que se olvidó de hacer eso .... – skaffman

+7

No hay tales métodos en el JDK, como se menciona en este informe de error: http://bugs.sun.com/bugdatabase/view_bug. Do? bug_id = 6907251 –

Respuesta

2

de Christian Semrau (en los comentarios de interrogación):

No hay tales métodos en el JDK, como se menciona en this bug report.

4

Esta es sólo una suposición, pero parte de la razón por la cual no se puede modificar una implementación no se proporcionó puede ser debido al hecho de que las interfaces NavigableSet/mapas exponen métodos mutantes que no están marcados como opcionales:

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

Dicho esto, parece razonable proporcionar una implementación no modificable para lanzar una UnsupportedOperationException. Eso es lo que se hace en estas implementaciones (que asumen que está utilizando Google Guava):

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

¡Bien hecho! No estoy familiarizado con "com.amazon.agua.collections". Me doy cuenta de que solo hace referencia al código Set en el código del Mapa, pero ¿hay algún paquete disponible públicamente donde se mantendrá esto? Sería una buena adición al JDK. –