Matriz Imutável em Java

Existe uma alternativa imutável para as matrizes primitivas em Java? Fazer um array primitivo final não impede que alguém faça algo como

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

Eu quero que os elementos da matriz sejam imutáveis.

Não com matrizes primitivas. Você precisará usar uma lista ou alguma outra estrutura de dados:

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

Minha recomendação é não usar um array ou uma lista unmodifiableList mas usar a ImmutableList de Guava , que existe para esse propósito.

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

Como outros notaram, você não pode ter matrizes imutáveis ​​em Java.

Se você realmente precisar de um método que retorne uma matriz que não influencie a matriz original, será necessário clonar a matriz toda vez:

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

Obviamente, isso é bastante caro (como você criará uma cópia completa toda vez que chamar o getter), mas se você não puder alterar a interface (para usar uma List por exemplo) e não puder arriscar o cliente a alterar seus internos, então pode ser necessário.

Essa técnica é chamada de fazer uma cópia defensiva.

Existe uma maneira de criar um array imutável em Java:

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

Matrizes com 0 elementos (obviamente) não podem sofrer mutação.

Isso pode realmente ser útil se você estiver usando o método List.toArray para converter uma List em uma matriz. Como até mesmo uma matriz vazia ocupa alguma memory, você pode salvar essa alocação de memory criando uma matriz vazia constante e sempre passando-a para o método toArray . Esse método alocará uma nova matriz se a matriz que você passar não tiver espaço suficiente, mas se ela existir (a lista estará vazia), ela retornará a matriz que você passou, permitindo que você reutilize essa matriz sempre que ligar para o toArray on uma List vazia.

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

Outra resposta

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

Se você precisar (por motivo de desempenho ou para economizar memory) nativo ‘int’ em vez de ‘java.lang.Integer’, provavelmente precisará escrever sua própria class de wrapper. Existem várias implementações do IntArray na rede, mas nenhuma (eu encontrei) era imutável: Koders IntArray , Lucene IntArray . Existem provavelmente outros.

Desde o goiaba 22, do pacote com.google.common.primitives você pode usar três novas classs, que têm um consumo de memory menor em comparação com o ImmutableList .

  • ImmutableIntArray
  • ImmutableLongArray
  • ImmutableDoubleArray

Eles também têm um construtor. Exemplo:

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

ou, se o tamanho for conhecido em tempo de compilation:

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

Esta é outra maneira de obter uma visão imutável de uma matriz para primitivos Java.

A partir do Java 9, você pode usar List.of(...) , JavaDoc .

Este método retorna uma List imutável e é muito eficiente.

Não, isso não é possível. No entanto, alguém poderia fazer algo assim:

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

Isso requer o uso de wrappers, e é uma lista, não uma matriz, mas é o mais próximo que você vai conseguir.

Em algumas situações, será mais leve usar esse método estático da biblioteca Google Guava: List Ints.asList(int... backingArray)

Exemplos:

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

Se você quiser evitar tanto a mutabilidade quanto o boxe, não há como sair da checkbox. Mas você pode criar uma class que contenha um array primitivo e forneça access somente leitura a elementos via método (s).

Embora seja verdade que Collections.unmodifiableList() funciona, às vezes você pode ter uma biblioteca grande com methods já definidos para retornar arrays (por exemplo, String[] ). Para evitar quebras, você pode realmente definir matrizes auxiliares que armazenarão os 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; } } 

Testar:

  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())); 

Não é perfeito, mas pelo menos você tem “arrays pseudo-imutáveis” (da perspectiva de class) e isso não vai quebrar o código relacionado.

O método de (elementos … E) em Java9 pode ser usado para criar uma lista imutável usando apenas uma linha:

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

O método acima retorna uma lista imutável contendo um número arbitrário de elementos. E adicionar qualquer número inteiro a essa lista resultaria na exceção java.lang.UnsupportedOperationException . Este método também aceita um único array como argumento.

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

Bem .. matrizes são úteis para passar como constantes (se fossem) como parâmetros de variantes.