¿Cuál es el sentido de ArrayList final?

¿Qué ventajas / desventajas podemos obtener haciendo ArrayList (u otra colección) final? Todavía puedo agregar nuevos elementos a ArrayList, eliminar elementos y actualizarlos. Pero, ¿qué efecto tiene hacer que sea final?

Pero, ¿qué efecto tiene hacer que sea final?

Esto significa que no puede volver a enlazar la variable para apuntar a una instancia de colección diferente:

final List list = new ArrayList(); list = new ArrayList(); // Since `list' is final, this won't compile 

Como una cuestión de estilo, declaro la mayoría de las referencias que no pretendo cambiar como final .

Todavía puedo agregar nuevos elementos a ArrayList, eliminar elementos y actualizarlos.

Si lo desea, puede evitar la inserción, eliminación, etc. mediante Collections.unmodifiableList() :

 final List list = Collections.unmodifiableList(new ArrayList(...)); 

Simplemente significa que no puede volver a asignar su referencia. Intentar hacer algo como lo siguiente dará lugar a un error del comstackdor.

 final List list = new ArrayList(); list = new LinkedList(); ^ Compiler error here 

Si realmente desea una lista inmutable, debe usar el método Collections.unmodifiableList() .

No podrá modificar su referencia utilizando una new ArrayList por ejemplo.

Al hacer que la variable sea final se asegura de que no se pueda volver a asignar esa referencia objest después de que se haya asignado. Como mencionas, aún puedes usar esa lista de métodos para hacer cambios.

Si combina la palabra clave final con el uso de Collections.unmodifiableList , puede conocer el comportamiento que probablemente esté tratando de lograr, por ejemplo:

 final List fixedList = Collections.unmodifiableList(someList); 

Esto tiene como resultado que la lista apuntada por fixedList no se puede cambiar. Sin embargo, tenga en cuenta que todavía se puede cambiar a través de la referencia someList (así que asegúrese de que esté fuera del scope después de esta asignación).

final tiene muchas consecuencias bajo multi threading.

  1. JMM define claramente que la finalización de la inicialización de un campo final está garantizada.

Lo que no está claramente definido es:

  1. Los comstackdores pueden reordenarlos a través de barreras de memoria.
  2. Los comstackdores siempre pueden leer una copia en caché.

No afecta lo que puede hacer con ArrayList como observa con razón: ArrayList en sí mismo es mutable. Acabas de hacer la referencia inmutable.

Pero hacer una variable final tiene otros beneficios:

  • Impide que la variable se modifique si se espera que se mantenga constante. Esto puede ayudar a prevenir futuros errores.
  • Hacer que las variables sean final puede ayudar al comstackdor a realizar ciertas optimizaciones de rendimiento.

En general, cuanto más cosas haces inmutables, mejor. Así que hacer referencias finales (incluso si son referencias a objetos mutables) es generalmente una buena idea.

Final es una palabra clave o palabra reservada en Java y se puede aplicar a variables miembro, métodos, clases y variables locales en Java. Una vez que hagas una referencia final, no puedes cambiar esa referencia y el comstackdor verificará esto y generará un error de comstackción si intentas reinicializar las variables finales en java.

No se puede volver a vincular a una colección diferente como se dijo.

Ejemplo: en conjunción con la implementación de listas inmutables, obtienes miembros seguros que puedes poner a disposición del público.

Ejemplo: Cuando confías en que la referencia no cambia, necesitas la final. Esto es cierto en los escenarios de sincronización, por ejemplo.

Puede haber muchos más ejemplos. Es un buen estilo declarar miembros finales si no tiene la intención de cambiar la referencia en absoluto.

Para obtener una lista realmente inmutable, tendrá que hacer copias en profundidad de los contenidos de la lista. UnmodifiableList solo haría la lista de referencias algo inmutable. Ahora hacer una copia profunda de la lista o matriz será difícil para la memoria con el tamaño en crecimiento. Puede hacer uso de la serialización / deserialización y almacenar la copia profunda de la matriz / lista en un archivo temporal. El colocador no estaría disponible ya que el miembro varaible necesita ser inmutable. El getter serializaría la variable miembro en un archivo y luego lo desializaría para obtener una copia profunda. La serialización tiene una naturaleza innata de ir a las profundidades de un árbol de objetos. Sin embargo, esto garantizaría la inmutabilidad completa a algún costo de rendimiento.

  package com.home.immutable.serial; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; public final class ImmutableBySerial { private final int num; private final String str; private final ArrayList immutableList; ImmutableBySerial(int num, String str, ArrayList list){ this.num = num; this.str = str; this.immutableList = getDeepCloned(list); } public int getNum(){ return num; } public String getStr(){ return str; } public ArrayList getImmutableList(){ return getDeepCloned(immutableList); } private ArrayList getDeepCloned(ArrayList list){ FileOutputStream fos = null; ObjectOutputStream oos = null; FileInputStream fis = null; ObjectInputStream ois = null; ArrayList clonedObj = null; try { fos = new FileOutputStream(new File("temp")); oos = new ObjectOutputStream(fos); oos.writeObject(list); fis = new FileInputStream(new File("temp")); ois = new ObjectInputStream(fis); clonedObj = (ArrayList)ois.readObject(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { oos.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } return clonedObj; } } 

Personalmente marcó el campo de colecciones de mis clases como final para evitar que los usuarios de mi clase verifiquen si es nulo o no. Esto funciona porque, una vez que el valor ya está asignado a una variable final, nunca puede reasignarse a otro valor, incluido el nulo.

Esencialmente, lo que estás tratando de lograr aquí es hacer que la lista sea inmutable, supongo. Sin embargo, cuando marca la lista final de referencia, implica que la referencia no puede apuntar a ningún otro objeto de lista que no sea este.

Si desea un ArrayList final (inmutable) vaya para el método de utilidad de la clase Collections Collections.unmodifaibleList (list) en su lugar.

Llegué a pensar en esta misma pregunta y código y ejemplo para agregar a la explicación desde otro ángulo.

La lista de arreglos final aún se puede modificar, consulte el ejemplo a continuación y ejecútelo para ver por usted mismo.

Aquí está la clase inmutable con la statement inmutable de la lista:

 public final class ImmutableClassWithArrayList { final List theFinalListVar = new ArrayList(); } 

Y aquí está el conductor:

 public class ImmutableClassWithArrayListTester { public static void main(String[] args) { ImmutableClassWithArrayList immClass = new ImmutableClassWithArrayList(); immClass.theFinalListVar.add("name"); immClass.theFinalListVar.forEach(str -> System.out.println(str)); } } 

Como puede ver, el método principal es agregar (modificar) la lista. Entonces, lo único que se debe tener en cuenta es que la “referencia” al objeto del tipo de colección no se puede reasignar a otro objeto. Como en la respuesta de adarshr anterior, no se puede hacer immClass.theFinalListVar = new ArrayList (); en el método principal aquí.

La parte de modificación realmente me ayudó a entender esto y espero que ayude de la misma manera.