Tipo Lista vs tipo ArrayList en Java [duplicado]
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
Entiendo que con (1), se pueden intercambiar implementaciones de la interfaz List . Parece que (1) se usa normalmente en una aplicación independientemente de la necesidad (yo siempre uso esto).
Me pregunto si alguien usa (2).
Además, ¿con qué frecuencia (y puedo darme un ejemplo) la situación realmente requiere el uso de (1) sobre (2) (es decir, cuando (2) no sería suficiente... aparte de la codificación de interfaces y mejores prácticas , etc.)
Casi siempre List
se prefiere ArrayList
porque, por ejemplo, List
se puede traducir a LinkedList
sin afectar el resto del código base.
Si se usa uno ArrayList
en lugar de List
, es difícil cambiar la ArrayList
implementación a LinkedList
uno porque ArrayList
se han usado métodos específicos en el código base que también requerirían una reestructuración.
Puede leer sobre las List
implementaciones aquí .
Puede comenzar con un ArrayList
, pero poco después descubrirá que otra implementación es la opción más adecuada.
Me pregunto si alguien usa (2).
Sí. Pero rara vez por una buena razón (en mi opinión).
Y la gente se quema porque consumieron ArrayList
cuando deberían haber consumido List
:
Los métodos de utilidad como
Collections.singletonList(...)
oArrays.asList(...)
no devuelven un archivoArrayList
.Los métodos de la
List
API no garantizan que se devuelva una lista del mismo tipo.
Por ejemplo, de alguien que se quema, en https://stackoverflow.com/a/1481123/139985 el cartel tuvo problemas con "cortar" porque ArrayList.sublist(...)
no devuelve un ArrayList
... y había diseñado su código para usarlo ArrayList
como el tipo de todas las variables de su lista. Terminó "resolviendo" el problema copiando la sublista en un nuevo archivo ArrayList
.
El argumento de que es necesario saber cómo se List
comporta se aborda en gran medida mediante el uso de la RandomAccess
interfaz del marcador. Sí, es un poco complicado, pero la alternativa es peor.
Además, ¿con qué frecuencia la situación realmente requiere el uso de (1) sobre (2) (es decir, cuando (2) no sería suficiente... aparte de la "codificación de interfaces" y las mejores prácticas, etc.)
La parte de la pregunta "con qué frecuencia" no tiene respuesta objetiva.
(y ¿puedo obtener un ejemplo?)
En ocasiones, la aplicación puede requerir que utilice métodos en la ArrayList
API que no están en la List
API. Por ejemplo ensureCapacity(int)
, trimToSize()
o removeRange(int, int)
. (Y el último solo surgirá si ha creado un subtipo de ArrayList que declara que el método es public
).
Esa es la única buena razón para codificar en la clase en lugar de en la interfaz, en mi opinión.
(Es teóricamente posible que obtenga una ligera mejora en el rendimiento... bajo ciertas circunstancias... en algunas plataformas... pero a menos que realmente necesite ese último 0,05%, no vale la pena hacerlo. Esto no es un buena razón, en mi opinión.)
No puedes escribir código eficiente si no sabes si el acceso aleatorio es eficiente o no.
Ese es un punto valido. Sin embargo, Java proporciona mejores formas de solucionar este problema; p.ej
public <T extends List & RandomAccess> void test(T list) {
// do stuff
}
Si llama a eso con una lista que no se implementa, RandomAccess
obtendrá un error de compilación.
También puedes probar dinámicamente... usando instanceof
... si la escritura estática es demasiado incómoda. E incluso podría escribir su código para usar diferentes algoritmos (dinámicamente) dependiendo de si una lista admite o no el acceso aleatorio.
Tenga en cuenta que ArrayList
no es la única clase de lista que implementa RandomAccess
. Otros CopyOnWriteList
incluyen Stack
y Vector
.
He visto gente hacer el mismo argumento sobre Serializable
(porque List
no lo implementa)... pero el enfoque anterior también resuelve este problema. (En la medida en que se pueda solucionar utilizando tipos de tiempo de ejecución. La ArrayList
serialización fallará si algún elemento no es serializable).
Finalmente, no voy a decir "porque es buen estilo". Esa "razón" es a la vez un argumento circular ("¿ Por qué es 'buen estilo'?") y una apelación a una autoridad superior no declarada (¡y probablemente inexistente!) ("¿ Quién dice que es 'buen estilo'?"). .
(Creo que es un buen estilo programar en la interfaz, pero no voy a dar esa razón. Es mejor que comprendas las verdaderas razones y llegues a las conclusiones correctas (en mi opinión) por ti mismo. La conclusión correcta puede no ser siempre la misma... dependiendo del contexto.)
Por ejemplo, puede decidir que a LinkedList
es la mejor opción para su aplicación, pero luego decide que ArrayList
podría ser una mejor opción por motivos de rendimiento.
Usar:
List list = new ArrayList(100); // will be better also to set the initial capacity of a collection
En lugar de:
ArrayList list = new ArrayList();
Para referencia:
(publicado principalmente para el diagrama de colección)