Pregunta

A menudo hago que un campo de colección no se pueda modificar antes de devolverlo desde un método getter:

private List<X> _xs;
....
List<X> getXs(){
  return Collections.unmodifiableList(_xs);
}

Pero no puedo pensar en una forma conveniente de hacerlo si la X anterior es en sí misma una Lista:

private List<List<Y>> _yLists;
.....
List<List<Y>> getYLists() {
  return Collections.unmodifiableList(_yLists);
}

El problema en lo anterior es, por supuesto, que aunque el cliente no puede modificar la Lista de listas, puede agregar / eliminar objetos Y de las listas incrustadas.

¿Alguna idea?

¿Fue útil?

Solución

Lo mejor que podría encontrar es ForwardingList from Google Collections . Los comentarios son bienvenidos.

private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) {
    return Collections.unmodifiableList(new ForwardingList<List<T>>() {
        @Override protected List<List<T>> delegate() {
            return Collections.unmodifiableList(input);
        }
        @Override public List<T> get(int index) {
            return Collections.unmodifiableList(delegate().get(index));
        }
    });
}

Otros consejos

desafortunadamente, no hay una manera fácil de lograr una profunda constancia en java. Tendría que hackearlo asegurándose siempre de que la lista dentro de la lista también sea inmodificable.

También me interesaría conocer alguna solución elegante.

Las colecciones de clojure (mapa, conjunto, lista, vector) se pueden anidar y son inmutables de forma predeterminada. Para java puro, hay esta biblioteca:

http://code.google.com/p/pcollections/

Si observa la implementación de los métodos Collections.unmodifiable * (...), puede ver que simplemente envuelven la colección. Hacer una utilidad profunda de la misma manera debería ser factible.

La desventaja de esto es que agrega una llamada de método adicional al acceso de recolección y por lo tanto afecta el rendimiento.

Si su único objetivo aquí es imponer la encapsulación, una solución clásica es usar clone () o similar para devolver una estructura que no sea el estado interno del objeto. Obviamente, esto solo funciona si todos los objetos se pueden clonar y si la estructura copiada es lo suficientemente pequeña.

Si esta es una estructura de datos que se usa con bastante frecuencia, otra opción es hacer que la API que accede a ella sea más concreta, para que tenga un control más detallado sobre las llamadas específicas. Escribir su propia implementación de la Lista, como se indica anteriormente, es una forma una de hacer esto, pero si puede limitar las llamadas a casos de uso específicos, puede exponer las API de acceso específicas en lugar de la interfaz de la Lista.

Por si alguien está interesado, aquí hay una solución simple:

    public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) {
        List<List<Double>> listWithUnmodifiableLists = new ArrayList<>();
            for (List<Double> list : nestedList) {              
                listWithUnmodifiableLists
                    .add(Collections.unmodifiableList(list));
            }
        return Collections.unmodifiableList(listWithUnmodifiableLists);
    }

Esto puede usarse, por ejemplo, como una solución si desea exponer una lista con un método getList (), puede devolver: toUnmodifiable (mNestedList), donde mNestedList es la lista privada en la clase.

Personalmente, me pareció útil cuando implementaba una clase utilizada para analizar con GSON en Android, ya que no tiene sentido poder modificar una respuesta, en este caso el json sin serializar, utilicé este método como un forma de exponer la lista con un captador y asegurarse de que la lista no se modifique.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top