La domanda è stata posta su come trasformare un array in un elenco. La maggior parte delle risposte finora ha mostrato come creare un nuovo elenco con gli stessi contenuti dell'array o riferito a librerie di terze parti. Tuttavia, esistono opzioni integrate semplici per questo tipo di conversione. Alcuni di essi sono già stati delineati in altre risposte (ad esempio questo ). Ma vorrei sottolineare ed elaborare alcuni gradi di libertà per l'implementazione qui, e mostrare i potenziali benefici, svantaggi e avvertenze.
Ci sono almeno due importanti distinzioni da fare:
- Se l'elenco risultante dovrebbe essere una vista sull'array o se dovrebbe essere un nuovo elenco
- Se l'elenco risultante dovrebbe essere modificabile o meno
Le opzioni verranno riassunte qui rapidamente e un fondo di esempio completo viene mostrato in fondo a questa risposta.
Creazione di un nuovo elenco anziché creazione di una vista sull'array
Quando il risultato dovrebbe essere un nuovo elenco, è possibile utilizzare uno degli approcci delle altre risposte:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
Ma bisogna considerare gli svantaggi di questo: un array con 1000000 long
valori occuperà circa 8 Megabyte di memoria. Il nuovo elenco occuperà anche circa 8 Megabyte. E, naturalmente, l'intero array deve essere attraversato durante la creazione di questo elenco. In molti casi, la creazione di un nuovo elenco non è semplicemente necessaria. È invece sufficiente creare una vista sull'array:
// 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);
(Vedi l'esempio in basso per un'implementazione del toList
metodo)
L'implicazione di avere una vista sull'array è che le modifiche nell'array saranno visibili nell'elenco:
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!
Fortunatamente, la creazione di una copia (ovvero un nuovo elenco non interessato dalle modifiche nell'array) dalla vista è banale:
List<Long> copy = new ArrayList<Long>(asList(array));
Ora, questa è una copia vera, equivalente a ciò che si ottiene con la soluzione basata sul flusso mostrata sopra.
Creazione di una vista modificabile o una vista non modificabile
In molti casi, sarà sufficiente quando l'elenco è di sola lettura . Il contenuto dell'elenco risultante spesso non verrà modificato, ma passerà solo all'elaborazione a valle che legge solo l'elenco.
Consentire la modifica dell'elenco solleva alcune domande:
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?
È possibile creare una vista elenco sull'array che è modificabile . Ciò significa che le modifiche nell'elenco, come l'impostazione di un nuovo valore su un determinato indice, saranno visibili nell'array.
Ma non è possibile creare una vista elenco strutturalmente modificabile . Ciò significa che non è possibile eseguire operazioni che incidono sulla dimensione dell'elenco. Questo semplicemente perché la dimensione dell'array sottostante non può essere modificata.
Di seguito è riportato un MCVE che mostra le diverse opzioni di implementazione e i possibili modi di utilizzare gli elenchi risultanti:
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();
}
}
L'output dell'esempio è mostrato qui:
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