Как наиболее эффективно скопировать содержимое списка в другой список - PullRequest
0 голосов
/ 03 марта 2020

У меня есть 2 больших списка, которые содержат тяжелые объекты, и мне нужно объединить их в один список. Моим первым инстинктом было создать новый список и добавить в него содержимое этих двух элементов следующим образом:

List<Item> items = new ArrayList<>();
items.addAll(list1);
items.addAll(list2);

Однако, поскольку это ArrayList для копирования этих двух больших списков, мне нужно выделить новый памяти вместо того, чтобы использовать существующий один раз и скопировать ссылки.

Теперь я думал о том, чтобы использовать LinkedList и скопировать конечный узел list1 в заголовок list2, насколько я могу сказать из В документации нет такого метода.

Есть ли лучший способ объединить 2 списка без перераспределения новой памяти? и если нет, то какова лучшая практика в таком случае?

Ответы [ 3 ]

3 голосов
/ 03 марта 2020

Это, пожалуй, самый эффективный способ памяти / G C:

List<Item> items = new ArrayList<>(list1.size() + list2.size());
items.addAll(list1);
items.addAll(list2);

Хитрость заключается в том, чтобы обеспечить точное capacity при создании списка; см. javado c. Это сохраняет любое двойное копирование для «увеличения» целевого списка (т. Е. list).

Теперь я думал использовать LinkedList и скопировать конечный узел list1 в заголовок list2 однако, насколько я могу судить из документации, такого метода не существует.

LinkedList использует больше памяти для каждой записи списка, чем ArrayList. Не менее чем в 4 раза.

Кроме того, когда вы используете addAll от одного LinkedList к другому, вы создаете новые объекты узла списка.


У меня есть 2 больших списка, которые содержат тяжелые объекты ....

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


Есть ли лучший способ объединить 2 списка без перераспределения новой памяти?

Невозможно объединить два экземпляра java.util.List без выделения дополнительной памяти. Лучшее, что вы можете сделать, - это минимизировать распределение.

С другой стороны ... если вы были готовы реализовать собственную структуру данных связанного списка, вы могли бы объединить два списка вместе с помощью соединяя их. Но вы List API не допускаете подобных вещей. (Для начала он искажает исходные списки.)


Это правда, что преждевременная оптимизация - это плохо. Однако, если у вас уже есть убедительные доказательства того, что списки будут большими, то это, вероятно, не преждевременно.

0 голосов
/ 03 марта 2020

Списки содержат ссылки на объекты, а не на сами объекты. Если вы не хотите создавать новый список, который должен иметь глубокую копию всех объектов.

  1. Если вы не возражаете против изменения одного из списков, добавьте все содержимое в один из списков и восстановить память из другого списка.
list1.addAll(list2);
list2.clear();

// You could also reclaim memory using garbage collector.

list1.addAll(list2);
list2 = null;
System.gc();     // It's not guaranteed that Garbage collector will be invoked.
Если вы хотите создать новый список, при этом назначьте емкость и освободите память из других списков, используя шаги, упомянутые в шаге (1).

Однако, это в основном зависит от того, как вы используете дело. Помните: -

Микрооптимизация - это root всего зла.

0 голосов
/ 03 марта 2020

Теперь я подумал о том, чтобы использовать LinkedList и скопировать конечный узел list1 в заголовок list2, однако, насколько я могу сказать из документации, такого метода нет.

Вы можете сделать то же самое, используя Array list следующим образом:

list1.addAll(list2);

И после добавления list2, вы можете попросить G C вернуть память, используемую list2, следующим образом:

list2 = null;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...