Создать изменяемый список из массива?

85

У меня есть массив, который я хотел бы превратить в List, чтобы изменить содержимое массива.

В Stack Overflow есть множество вопросов / ответов, которые касаются Arrays.asList()и того, как он предоставляет только представление списка базового массива, и то, как попытка манипулировать полученным списком обычно вызывает UnsupportedOperationExceptionметоды, используемые для управления списком (например add(), remove()и т. Д.) не реализовано реализацией List, предоставленной Arrays.asList().

Но я не могу найти пример того, как превратить массив в изменяемый список. Я полагаю, что могу перебрать массив и put()каждое значение в новый список, но мне интересно, существует ли интерфейс, который бы сделал это за меня.

Ericoco
источник

Ответы:

122

Один простой способ:

Foo[] array = ...;
List<Foo> list = new ArrayList<Foo>(Arrays.asList(array));

Это создаст изменяемый список, но он будет копией исходного массива. Изменение списка не изменит массив. Вы, конечно, можете скопировать его позже, используя toArray.

Если вы хотите создать изменяемое представление массива, я считаю, что вам придется реализовать это самостоятельно.

Джон Скит
источник
2
Arrays.asList возвращает представление массива с поддержкой тех методов изменения, которые не влияют на размер списка
Тимо Весткемпер
1
@ jon-skeet Я знаю, я просто сказал, что Arrays.asList дает вам список с поддержкой массива с ограниченной изменчивостью, если вам нужно добавить / удалить / вставить, тогда упаковка ArrayList - лучший подход.
Timo Westkämper
4
В Java необходимо четко обозначить изменчивость / неизменяемость всех этих статических фабричных методов. Обидно узнать, что вы сделали неизменяемую вещь во время выполнения.
Dustinevan
1
@dustinevan: Документация довольно ясна. ИМО: «Возвращает список фиксированного размера, подкрепленный указанным массивом. (Изменения в возвращаемом списке« записывают »в массив.)»
Джон Скит
1
@JonSkeet не хочет тратить ваше время - спасибо за все, что вы делаете. Я просто хотел бы проголосовать за прояснение самих названий - я уверен, что документы ясны. Некоторые из нас танцуют между языками, и это достаточно ясно для других языков.
dustinevan
23

И если вы используете API коллекции Google (Guava):

Lists.newArrayList(myArray);
всингх
источник
1
Это самый лаконичный ответ. Благодарю.
eugene82
2
Даже сама Guava рекомендует использовать любой из них new ArrayList<>(Arrays.asList(...))- javadoc для метода подразумевает, что он станет устаревшим, потому что он недостаточно полезен.
Logan Pickup
1
2020 и все еще не устарел. Прыгай!
markthegrea
13

Этот простой код с использованием Stream API, включенного в Java 8, создает изменяемый список (или представление), содержащий элементы вашего массива:

Foo[] array = ...;
List<Foo> list = Stream.of(array).collect(Collectors.toCollection(ArrayList::new));

Или, что одинаково верно:

List<Foo> list = Arrays.stream(array).collect(Collectors.toCollection(ArrayList::new));
MikaelF
источник
4

Если вы используете Eclipse Collections (ранее GS Collections ), вы можете использовать FastList.newListWith(...)или FastList.wrapCopy(...).

Оба метода принимают varargs, поэтому вы можете создать встроенный массив или передать существующий массив.

MutableList<Integer> list1 = FastList.newListWith(1, 2, 3, 4);

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);

Разница между двумя методами заключается в том, копируется ли массив. newListWith()не копирует массив и, следовательно, занимает постоянное время. Вам следует избегать его использования, если вы знаете, что массив может быть изменен в другом месте.

Integer[] array2 = {1, 2, 3, 4};
MutableList<Integer> list2 = FastList.newListWith(array2);
array2[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 5, 3, 4), list2);

Integer[] array3 = {1, 2, 3, 4};
MutableList<Integer> list3 = FastList.wrapCopy(array3);
array3[1] = 5;
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), list3);

Примечание: я являюсь участником коллекций Eclipse.

Крейг П. Мотлин
источник
1
У вас есть хороший API коллекций. Первый, который я видел, который может соблазнить меня от моих собственных реализаций ... единственное, чего мне кажется не хватает, что я считаю в целом полезным, - это реализация отсортированного набора, поддерживаемая массивом (который, как я считаю, намного более эффективен, чем реализация на основе дерева либо для данных, которые редко изменяются, либо для наборов, которые могут изменяться часто, но обычно содержат менее 10 или около того элементов).
Жюль
0
myNewArrayList = new ArrayList<>(Arrays.asList(myArray));
Сид
источник
1
@JonSkeet, я знаю, что ваш комментарий от 2012 года, и я живу в будущем, но я предполагаю, что этот комментарий не выдержал, учитывая, что моя IDE специально подчеркивает и говорит: «Эй, не объявляйте это с помощью заявленный тип. там он вам не нужен "?
Brent Thoenen
1
@BrentThoenen: Я не понимаю вашего комментария. Вы заметили, что мой комментарий относится к ревизии 1, которая использовалась myNewArrayList = new ArrayList(...), то есть к необработанному типу? Существует разница между «использованием оператора ромба, чтобы компилятор мог определить аргумент типа» и «использованием необработанного типа».
Джон Скит,
1
Я опубликовал этот ответ и все это время жил в забвении, когда сам @JonSkeet прокомментировал мой ответ. Спасибо, Брент, за комментарий.
Сид
@JonSkeet ах, моя плохая. я не проверял версию, которую вы комментировали. Я ошибся в том, что Java 2012 года также предполагала пустой алмазный оператор как необработанный тип. Это мой б. Спасибо за ответ!
Brent Thoenen
0

Добавление еще одного варианта с использованием Streams API:

List<Foo> list = Arrays.stream(array).collect(Collectors.toList());
Сахил Чабра
источник
2
Проблема с вашим решением заключается в том, что Collectors # toList не имеет гарантии изменчивости и, следовательно, не соответствует требованиям.
MikaelF