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


85

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

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

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

Ответы:


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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.