2008-10-22 24 views
27

En el espíritu de Best Practices: Always return a ____, never a ____, me enfrento a una pregunta similar en mi próxima migration from JDK1.4.2 to JDK5 and more. (Sí, I saber, JDK1.4.2 is EOL! ;-)).API java 5 y más: ¿Debo devolver una matriz o una colección?

Para funciones que devuelven una colección (que no son simples property collections), siempre prefiero (en JDK1.4.2) devuelve una matriz en lugar de una lista genérica, debido a que:

  • se aplica el tipo de regresar (MyObject[] en lugar de la lista de objetos, mucho más de tipo seguro en una estática - como en 'compilación' - nivel)
  • que sugiere un 'sólo lectura' carácter a la colección devuelta (es más complicado agregar un ele a la colección, aunque esto no es tan riguroso como la palabra clave de "solo lectura" en C#). Esto no es lo mismo que decir que es 'inmutable' ya que las referencias encontradas en la matriz todavía pueden ser modificados ...

Por supuesto, yo siempre crear esta volvió array (No exponga ninguno ' matriz interna)

Ahora, en JDK5 y más, podría usar List<MyObject> si quiero.

¿Cuáles son las buenas razones para elegir devolver MyObject[] en lugar de List o Collection<MyObject> al codificar en java5?

bonificación, si se utiliza Collection<MyObject>, es posible:

  • cumplir un atributo de sólo lectura en la colección devuelta? (no add() o remove() posible)
  • ¿imponer un aspecto inmutable a la colección devuelta? (incluso las referencias de esa colección no se pueden modificar)

PD: El JavaGenericFAQ no tenía exactamente eso.

Respuesta

34

Preferir la recopilación (o lista, o establecer según corresponda) a una matriz. Con los genéricos se obtiene la verificación de tipo que faltaba antes de Java 5. Además, al exponer solo la interfaz, es libre de cambiar la implementación más tarde (por ejemplo, cambiar una Lista de Arrajes por una Lista Vinculada).

Las matrices y los genéricos no se mezclan muy bien. Por lo tanto, si desea aprovechar los genéricos, debe generalmente evitar arreglos.
Es decir: no puede crear genéricamente una matriz. Por ejemplo, si T es un tipo genérico, entonces "new T [0]" no compila. Tendría que hacer algo como "(T []) nuevo Objeto [0]", que genera una advertencia de lanzamiento no seleccionada. Por la misma razón, no puede usar tipos genéricos con varargs sin advertencias.

Al usar Collections.unmodifiableCollection (y métodos similares), obtienes la restricción de solo lectura (que no puedes lograr con una matriz; tendrías que devolver una copia de la matriz).

No se puede forzar la inmutabilidad de los miembros, pero tampoco se puede hacer eso con una matriz.

+0

Gracias! +1 por ahora (esperaré un poco para obtener otras respuestas). Se puede decir que aún no he leído seriamente el javadoc JDK6 ...;) – VonC

+0

"Las matrices y los genéricos no se mezclan muy bien. Por lo tanto, si desea aprovechar los genéricos, generalmente debería evitar los arreglos". -> Urg? ¿Puedes explicar esta parte? Mis matrices se mezclan bien con mis genéricos ... – Nicolas

+0

No puede crear genéricamente una matriz. Por ejemplo, si T es un tipo genérico, entonces "new T [0]" no compila. Tendría que hacer algo como "(T []) nuevo Objeto [0]", que genera una advertencia de lanzamiento no seleccionada. Por la misma razón, no puede usar tipos genéricos con varargs sin advertencias. –

3

Echa un vistazo a los métodos * no modificables en la clase Collections para hacer colecciones devueltas de solo lectura/inmutables. Esto envolverá la colección original en una lista que impide el acceso a cambiar la lista en sí (los elementos en sí mismos no son inmutables).

unmodifiableList por ejemplo.

Para mí, depende de cómo se usará la lista devuelta. ¿A qué otros métodos se está transfiriendo y cómo se usará? En general, preferiría la colección genérica sobre una matriz, pero la cambiaría caso por caso.

La matriz probablemente también funcionará más rápido si está haciendo algo crítico.

+0

no hay proceso en tiempo real involucrado aquí. Y la colección no representa una "propiedad", solo un valor calculado. – VonC

2

Mi respuesta fue negativa porque utilizo el proxy para la clase y el uso de ese tipo de cosas (proxy y reflexión) es forzado porque afecta el rendimiento de las mentes de algunas personas (muchas personas ni siquiera usan el reflejo, sin embargo usan hibernación y resorte que usa la relfection, class proxy y xml).

Potenciador del proyecto cglib.sourceforge.net, permite crear proxy para clases (JDK solo admite proxies para interfaces). Proxy le permite controlar los métodos en el objeto, sin embargo, no puede acceder a los campos utilizando reflexiones. si tiene alguna pregunta, pregunte.

+0

Gracias por el código y las precisiones. +1, pero es posible que no use ese tipo de capa adicional en mi código pronto ... – VonC

+0

Lo entiendo, pero lo que realmente quiero decir es que se usa Collections.unmodifiableCollection. No le da nada hasta que no modifique su colección. –

10

En realidad, las matrices aún tienen una ventaja sobre Colecciones/Listas. Debido a la forma en que Java implementa Genéricos a través del borrado de tipos, no puede tener dos métodos que toman Colecciones como argumentos, pero solo difieren según el tipo genérico de la Colección.

Ex:

public void doSomething(Collection<String> strs) { ... } 
public void doSomething(Collection<Integer> ints) { ... } 

Los dos métodos anteriores no se compilará porque el compilador javac utiliza tipo de borrado y por lo tanto no puede pasar la información de tipo a la JVM. La JVM solo verá dos métodos que toman una colección como argumento.

En los casos anteriores, la mejor solución es hacer que los métodos tomen arrays como argumentos y usar el método Collection/List toArray() al pasarles los argumentos. Si aún desea usar Collection/List dentro de los métodos anteriores, simplemente use el método java.util.Arrays.asList() para recuperar su Lista.

Ex:

public void doSomething(String[] strs) { 
     List<String> strList = Arrays.asList(strs); 
     ... 
} 

public void doSomething(Integer[] ints) { 
     List<Integer> intList = Arrays.asList(ints); 
     ... 
} 

public static void main(String[] args) { 
     List<String> strs = new ArrayList<String>(); 
     List<Integer> ints = new ArrayList<Integer>(); 
     obj.doSomething(strs.toArray()); 
     obj.doSomething(ints.toArray()); 
} 
+1

Excelente punto. Gracias por señalar eso. – VonC

Cuestiones relacionadas