Питання задавали питання про те, як перетворити масив у список. Більшість відповідей поки що показували, як створити новий список з тим самим вмістом, що і масив, або посилатися на сторонні бібліотеки. Однак існують прості, вбудовані варіанти такого типу перетворення. Деякі з них уже замальовані в інших відповідях (наприклад, у цій ). Але я хотів би зазначити та розробити певні ступені свободи для здійснення тут, а також показати потенційні переваги, недоліки та застереження.
Потрібно зробити принаймні дві важливі відмінності:
- Незалежно від того, чи повинен у списку бути перегляд масиву, чи має бути новий список
- Незалежно від того, має бути змінений список, що змінюється, чи ні
Варіанти будуть узагальнені тут швидко, а внизу цієї відповіді показано повний приклад програми.
Створення нового списку проти створення представлення масиву
Коли результат повинен бути новим списком, то може бути використаний один із підходів з інших відповідей:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
Але слід врахувати недоліки цього: масив зі 1000000 long
значеннями займе приблизно 8 мегабайт пам'яті. Новий список також займе приблизно 8 мегабайт. І звичайно, під час створення цього списку необхідно пройти повний масив. У багатьох випадках створювати новий список просто не потрібно. Натомість достатньо створити подання на масив:
// 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);
(Дивіться приклад внизу щодо реалізації toList
методу)
Мається на увазі наявність представлення масиву в тому, що зміни в масиві будуть видимі у списку:
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!
На щастя, створення копії (тобто нового списку, який не впливає на зміни в масиві) з представлення тривіальне:
List<Long> copy = new ArrayList<Long>(asList(array));
Тепер це справжня копія, еквівалентна тому, що досягається за допомогою потокового рішення, яке було показано вище.
Створення змінюваного виду або незмінний виду
У багатьох випадках цього буде достатньо, коли список доступний лише для читання . Вміст результуючого списку часто не змінюватиметься, а передається лише для подальшої обробки, яка лише читає список.
Якщо дозволити зміни списку, виникають деякі питання:
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?
На масиві, який може змінюватися, можна створити подання списку . Це означає, що зміни в списку, як-от встановлення нового значення на певний індекс, будуть видимі в масиві.
Але неможливо створити перелік списку, який структурно змінюється . Це означає, що неможливо робити операції, які впливають на розмір списку. Це просто тому, що розмір основного масиву неможливо змінити.
Далі наведено MCVE, що показує різні варіанти реалізації та можливі способи використання отриманих списків:
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();
}
}
Вихід прикладу показаний тут:
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