singletonlist objeto inmutable inmutabilidad java arrays immutability

objeto - Arreglo inmutable en Java



objeto inmutable java (14)

¿Hay una alternativa inmutable a las matrices primitivas en Java? Hacer una matriz primitiva final realidad no evita que uno haga algo como

final int[] array = new int[] {0, 1, 2, 3}; array[0] = 42;

Quiero que los elementos de la matriz sean inmutables.


A partir de Java 9 puede usar List.of(...) , JavaDoc .

Este método devuelve una List inmutable y es muy eficiente.


Bueno ... las matrices son útiles para pasar como constantes (si lo fueran) como parámetros de variantes.


Como otros han notado, no puedes tener matrices inmutables en Java.

Si necesitas absolutamente un método que devuelva una matriz que no influya en la matriz original, entonces necesitarás clonar la matriz cada vez:

public int[] getFooArray() { return fooArray == null ? null : fooArray.clone(); }

Obviamente, esto es bastante caro (ya que creará una copia completa cada vez que llame al captador), pero si no puede cambiar la interfaz (para usar una List por ejemplo) y no puede arriesgarse a que el cliente cambie sus partes internas, entonces puede ser necesario.

Esta técnica se llama hacer una copia defensiva.


Desde Guava 22, desde el paquete com.google.common.primitives , puede usar tres nuevas clases, que tienen una huella de memoria menor en comparación con ImmutableList .

También tienen un constructor. Ejemplo:

int size = 2; ImmutableLongArray longArray = ImmutableLongArray.builder(size) .add(1L) .add(2L) .build();

o, si el tamaño se conoce en tiempo de compilación:

ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);

Esta es otra forma de obtener una vista inmutable de una matriz para primitivas de Java.


El método JavaDoc en Java9 se puede usar para crear una lista inmutable usando solo una línea:

List<Integer> items = List.of(1,2,3,4,5);

El método anterior devuelve una lista inmutable que contiene una cantidad arbitraria de elementos. Y agregar cualquier número entero a esta lista daría como resultado la excepción java.lang.UnsupportedOperationException . Este método también acepta una única matriz como argumento.

String[] array = ... ; List<String[]> list = List.<String[]>of(array);


En algunas situaciones, será más ligero usar este método estático de la biblioteca de Google Guava: List<Integer> Ints.asList(int... backingArray)

Ejemplos:

  • List<Integer> x1 = Ints.asList(0, 1, 2, 3)
  • List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})

Hay una forma de hacer una matriz inmutable en Java:

final String[] IMMUTABLE = new String[0];

Las matrices con 0 elementos (obviamente) no pueden ser mutadas.

Esto puede ser útil si está utilizando el método List.toArray para convertir una List en una matriz. Dado que incluso una matriz vacía ocupa algo de memoria, puede guardar esa asignación de memoria creando una matriz vacía constante y siempre pasándola al método toArray . Ese método asignará una nueva matriz si la matriz que pasa no tiene suficiente espacio, pero si lo hace (la lista está vacía), devolverá la matriz que pasó, lo que le permite reutilizar dicha matriz cada vez que llame a toArray en una List vacía.

final static String[] EMPTY_STRING_ARRAY = new String[0]; List<String> emptyList = new ArrayList<String>(); return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY


Mi recomendación es no utilizar una matriz o una lista unmodifiableList sino utilizar la Guava de Guava , que existe para este fin.

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);


No con arreglos primitivos. Tendrá que usar una lista o alguna otra estructura de datos:

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));


No, esto no es posible Sin embargo, uno podría hacer algo como esto:

List<Integer> temp = new ArrayList<Integer>(); temp.add(Integer.valueOf(0)); temp.add(Integer.valueOf(2)); temp.add(Integer.valueOf(3)); temp.add(Integer.valueOf(4)); List<Integer> immutable = Collections.unmodifiableList(temp);

Esto requiere el uso de contenedores, y es una lista, no una matriz, pero es lo más cercano que obtendrá.


Otra respuesta

static class ImmutableArray<T> { private final T[] array; private ImmutableArray(T[] a){ array = Arrays.copyOf(a, a.length); } public static <T> ImmutableArray<T> from(T[] a){ return new ImmutableArray<T>(a); } public T get(int index){ return array[index]; } } { final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"}); }


Si bien es cierto que Collections.unmodifiableList() funciona, a veces puede tener una gran biblioteca con métodos ya definidos para devolver matrices (por ejemplo, String[] ). Para evitar romperlos, puede definir matrices auxiliares que almacenarán los valores:

public class Test { private final String[] original; private final String[] auxiliary; /** constructor */ public Test(String[] _values) { original = new String[_values.length]; // Pre-allocated array. auxiliary = new String[_values.length]; System.arraycopy(_values, 0, original, 0, _values.length); } /** Get array values. */ public String[] getValues() { // No need to call clone() - we pre-allocated auxiliary. System.arraycopy(original, 0, auxiliary, 0, original.length); return auxiliary; } }

Probar:

Test test = new Test(new String[]{"a", "b", "C"}); System.out.println(Arrays.asList(test.getValues())); String[] values = test.getValues(); values[0] = "foobar"; // At this point, "foobar" exist in "auxiliary" but since we are // copying "original" to "auxiliary" for each call, the next line // will print the original values "a", "b", "c". System.out.println(Arrays.asList(test.getValues()));

No es perfecto, pero al menos tiene "matrices pseudo inmutables" (desde la perspectiva de la clase) y esto no romperá el código relacionado.


Si desea evitar la mutabilidad y el boxeo, no hay forma de salir de la caja. Pero puede crear una clase que contenga una matriz primitiva dentro y que proporcione acceso de solo lectura a los elementos a través de los métodos.


Si necesita (por razones de rendimiento o para guardar memoria) ''int'' nativo en lugar de ''java.lang.Integer'', entonces probablemente necesite escribir su propia clase contenedora. Hay varias implementaciones de IntArray en la red, pero ninguna (que encontré) era inmutable: Koders IntArray , Lucene IntArray . Probablemente haya otros.