java - lists - ¿Cómo crear una colección profunda no modificable?
lists java (6)
A menudo hago un campo de colección no modificable 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 de arriba 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?
En caso de que alguien esté interesado aquí, es 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 se puede usar, 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 de la clase.
Personalmente encontré esto útil al implementar una clase utilizada para analizar con GSON en Android, ya que no tiene sentido poder modificar una respuesta, en este caso el json deserializado, utilicé este método como una forma de exponer la lista con un getter y se aseguró de que la lista no se modifique.
Lo mejor que se me ocurre es utilizar ForwardingList de 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));
}
});
}
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 extra al acceso de recolección y, por lo tanto, afecta el rendimiento.
Si su único objetivo aquí es hacer cumplir 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 se pueden clonar todos los objetos y si la estructura copiada es lo suficientemente pequeña.
Si esta es una estructura de datos utilizada comúnmente, otra opción es hacer que la API que accede a ella sea más concreta, para que tenga un control más detallado de las llamadas específicas. Escribir su propia implementación de lista, como se indica arriba, es una forma de hacerlo, pero si puede reducir las llamadas a casos de uso específicos, puede exponer API de acceso específico en lugar de la interfaz de lista.
desafortunadamente, no hay una manera fácil de obtener una constidad profunda en Java. tendrías que hackearlo asegurándote siempre de que la lista dentro de la lista tampoco sea modificable.
También me interesaría conocer cualquier solución elegante.
Las colecciones de clojure (mapa, conjunto, lista, vector) pueden anidarse y son inmutables por defecto. Para Java puro, hay esta biblioteca: