2011-05-13 11 views
9

Tengo curiosidad por lo que se considera una mejor práctica al devolver una colección de objetos de una clase mutable:¿Cuál es la mejor práctica para devolver una colección interna en Java?

public class Someclass { 

    public List<String> strings; 

    public add(String in){ strings.add(in); } 
    public remove(String in) { strings.remove(in); } 

    //THIS 
    public List<String> getStrings(){ 
    return Collections.unmodifiableList(strings); 
    } 

    //OR THIS 
    public List<String> getStrings(){ 
    return new ArrayList(strings); 
    } 
} 

Siempre he asumido envolviendo la recolección interna en un inmodificable fue el mejor enfoque, ya que no vi una razón para incurrir en la sobrecarga de crear una copia. Sin embargo, se me ocurrió que cualquier cambio realizado en la lista internamente quedaría expuesto al cliente, lo que me parece malo.

Respuesta

5

No creo que haya una respuesta simple de "mejores prácticas" para esto. Realmente depende de la cantidad de recursos de la máquina que esté dispuesto a gastar para evitar la violación de los límites de abstracción de datos de las clases. Y depende de los riesgos que en realidad está tratando de mitigar; p.ej. ¿se trata de errores simples (no concurrentes), errores de concurrencia o filtraciones de información?

Las opciones son:

  • No hacer nada; es decir, devolver la colección tal como está.
  • Devuelva la colección envuelta en una clase de envoltura inmutable.
  • Devuelva una copia superficial de la colección.
  • Devuelva una copia profunda de la colección.

Además de los costos directos de copia, otros factores relacionados con el rendimiento son el uso de memoria y la generación de basura y el impacto en la concurrencia. Por ejemplo, si varios subprocesos están actualizando la colección y/o "obteniéndola", entonces hacer una copia de la colección generalmente implica bloquearla ... lo que podría convertir a la operación en un cuello de botella de simultaneidad.

En resumen, debe equilibrar las implicaciones de costo/rendimiento con los riesgos y costos potenciales o reales de no tomar las precauciones.

1

Me gusta hacer esto último, pero usando el método .clone().

+0

El último enfoque, el uso de ArrayList nuevo, o el uso de .clone(), es el enfoque correcto para reducir los problemas de concurrencia. Collections.unmodifiableList() aumenta los posibles problemas de concurrencia en un entorno de subprocesos múltiples. –

0

Si le preocupa exponer los cambios; y su objeto implementa Cloneable, luego puede devolver una copia profunda clonada de su lista de objetos al invocador.

0

'nueva ArrayList (cadenas)' es más segura que 'Collections.unmodifiableList (cadenas)'.

Porque Collections.unmodifiableList acaba de reenviar la lista de fuentes.

muestra:

List<String> list1 = someclass.getStrings(); //Use Collections.unmodifiableList(strings) implementation 
List<String> list2 = someclass.getStrings(); //Use new ArrayList(strings) implementation 

someclass.add("foo"); 

Ahora, verá se añade lista1! list2 no.

Cuestiones relacionadas