La pregunta se refería a cómo convertir una matriz en una lista. La mayoría de las respuestas hasta ahora mostraban cómo crear una nueva lista con el mismo contenido que la matriz o referidas a bibliotecas de terceros. Sin embargo, hay opciones simples e integradas para este tipo de conversión. Algunos de ellos ya han sido bosquejados en otras respuestas (por ejemplo, esta ). Pero me gustaría señalar y elaborar ciertos grados de libertad para la implementación aquí, y mostrar los posibles beneficios, inconvenientes y advertencias.
Hay al menos dos distinciones importantes que deben hacerse:
- Si la lista resultante debería ser una vista en la matriz o si debería ser una nueva lista
- Si la lista resultante debe ser modificable o no
Las opciones se resumirán aquí rápidamente, y se muestra un programa de ejemplo completo al final de esta respuesta.
Crear una nueva lista versus crear una vista en la matriz
Cuando el resultado debe ser una lista nueva , se puede utilizar uno de los enfoques de las otras respuestas:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
Pero uno debería considerar los inconvenientes de hacer esto: una matriz con 1000000 long
valores ocupará aproximadamente 8 megabytes de memoria. La nueva lista también ocupará aproximadamente 8 megabytes. Y, por supuesto, la matriz completa debe atravesarse al crear esta lista. En muchos casos, crear una nueva lista simplemente no es necesario. En cambio, es suficiente crear una vista en la matriz:
// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }
// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);
(Vea el ejemplo en la parte inferior para una implementación del toList
método)
La implicación de tener una vista en la matriz es que los cambios en la matriz serán visibles en la lista:
long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);
System.out.println(list.get(1)); // This will print 34
// Modify the array contents:
array[1] = 12345;
System.out.println(list.get(1)); // This will now print 12345!
Afortunadamente, crear una copia (es decir, una nueva lista que no se ve afectada por las modificaciones en la matriz) desde la vista es trivial:
List<Long> copy = new ArrayList<Long>(asList(array));
Ahora, esta es una copia verdadera, equivalente a lo que se logra con la solución basada en flujo que se mostró arriba.
Crear una vista modificable o una vista no modificable
En muchos casos, será suficiente cuando la lista sea de solo lectura . El contenido de la lista resultante a menudo no se modificará, sino que solo se pasará al procesamiento posterior que solo lee la lista.
Permitir modificaciones de la lista plantea algunas preguntas:
long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);
list.set(2, 34567); // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null); // What should happen here?
list.add(99999); // Should this be possible?
Es posible crear una vista de lista en la matriz que sea modificable . Esto significa que los cambios en la lista, como establecer un nuevo valor en un cierto índice, serán visibles en la matriz.
Pero no es posible crear una vista de lista que sea estructuralmente modificable . Esto significa que no es posible realizar operaciones que afecten el tamaño de la lista. Esto es simplemente porque el tamaño de la matriz subyacente no se puede cambiar.
El siguiente es un MCVE que muestra las diferentes opciones de implementación y las posibles formas de usar las listas resultantes:
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;
public class PrimitiveArraysAsLists
{
public static void main(String[] args)
{
long array[] = { 12, 34, 56, 78 };
// Create VIEWS on the given array
List<Long> list = asList(array);
List<Long> unmodifiableList = asUnmodifiableList(array);
// If a NEW list is desired (and not a VIEW on the array), this
// can be created as well:
List<Long> copy = new ArrayList<Long>(asList(array));
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Modify a value in the array. The changes will be visible
// in the list and the unmodifiable list, but not in
// the copy.
System.out.println("Changing value at index 1 of the array...");
array[1] = 34567;
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Modify a value of the list. The changes will be visible
// in the array and the unmodifiable list, but not in
// the copy.
System.out.println("Changing value at index 2 of the list...");
list.set(2, 56789L);
System.out.println("array : " + Arrays.toString(array));
System.out.println("list : " + list);
System.out.println("unmodifiableList: " + unmodifiableList);
System.out.println("copy : " + copy);
// Certain operations are not supported:
try
{
// Throws an UnsupportedOperationException: This list is
// unmodifiable, because the "set" method is not implemented
unmodifiableList.set(2, 23456L);
}
catch (UnsupportedOperationException e)
{
System.out.println("Expected: " + e);
}
try
{
// Throws an UnsupportedOperationException: The size of the
// backing array cannot be changed
list.add(90L);
}
catch (UnsupportedOperationException e)
{
System.out.println("Expected: " + e);
}
try
{
// Throws a NullPointerException: The value 'null' cannot be
// converted to a primitive 'long' value for the underlying array
list.set(2, null);
}
catch (NullPointerException e)
{
System.out.println("Expected: " + e);
}
}
/**
* Returns an unmodifiable view on the given array, as a list.
* Changes in the given array will be visible in the returned
* list.
*
* @param array The array
* @return The list view
*/
private static List<Long> asUnmodifiableList(long array[])
{
Objects.requireNonNull(array);
class ResultList extends AbstractList<Long> implements RandomAccess
{
@Override
public Long get(int index)
{
return array[index];
}
@Override
public int size()
{
return array.length;
}
};
return new ResultList();
}
/**
* Returns a view on the given array, as a list. Changes in the given
* array will be visible in the returned list, and vice versa. The
* list does not allow for <i>structural modifications</i>, meaning
* that it is not possible to change the size of the list.
*
* @param array The array
* @return The list view
*/
private static List<Long> asList(long array[])
{
Objects.requireNonNull(array);
class ResultList extends AbstractList<Long> implements RandomAccess
{
@Override
public Long get(int index)
{
return array[index];
}
@Override
public Long set(int index, Long element)
{
long old = array[index];
array[index] = element;
return old;
}
@Override
public int size()
{
return array.length;
}
};
return new ResultList();
}
}
La salida del ejemplo se muestra aquí:
array : [12, 34, 56, 78]
list : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy : [12, 34, 56, 78]
Changing value at index 1 of the array...
array : [12, 34567, 56, 78]
list : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy : [12, 34, 56, 78]
Changing value at index 2 of the list...
array : [12, 34567, 56789, 78]
list : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy : [12, 34, 56, 78]
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.NullPointerException