Mam, List<SomeBean>
który jest wypełniany z usługi sieci Web. Chcę skopiować / sklonować zawartość tej listy do pustej listy tego samego typu. Wyszukiwanie w Google dotyczące kopiowania listy zasugerowało mi użycie Collections.copy()
metody. We wszystkich przykładach, które widziałem, lista docelowa miała zawierać dokładną liczbę elementów do skopiowania.
Ponieważ lista, której używam, jest wypełniana za pośrednictwem usługi internetowej i zawiera setki obiektów, nie mogę użyć powyższej techniki. Albo źle go używam ?? !! W każdym razie, aby to zadziałało, próbowałem zrobić coś takiego, ale nadal mam plik IndexOutOfBoundsException
.
List<SomeBean> wsList = app.allInOne(template);
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());
Próbowałem użyć, wsListCopy=wsList.subList(0, wsList.size())
ale dostałem ConcurrentAccessException
później w kodzie. Uderzenie i próba. :)
W każdym razie moje pytanie jest proste, jak mogę skopiować całą zawartość mojej listy do innej listy? Oczywiście nie poprzez iterację.
źródło
app.allInOne(template)
?ArrayList
?Odpowiedzi:
Po prostu użyj tego:
List<SomeBean> newList = new ArrayList<SomeBean>(otherList);
Uwaga: nadal nie jest bezpieczny wątkowo, jeśli modyfikujesz
otherList
z innego wątku, możesz chcieć zrobić tootherList
(a nawetnewList
)CopyOnWriteArrayList
na przykład - lub użyć prymitywu blokady, takiego jak ReentrantReadWriteLock, aby serializować dostęp do odczytu / zapisu do dowolnych list jednocześnie dostępne.źródło
ConcurrentAccessException
.To naprawdę fajny sposób na zrobienie tego w Javie 8:
Oczywiście zaletą jest to, że możesz filtrować i przeskakiwać tylko do kopii części listy.
na przykład
//don't copy the first element List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
źródło
list
zostanie zmieniony, gdy kolektor jest uruchomiony,ConcurrentModificationException
rzuca się a..limit(list1.size() - 1)
Pamiętaj, że za każdym razem, gdy używasz metody addAll () do kopiowania, zawartość obu list tablic (originalArrayList i copyArrayofList) odniesień do tych samych obiektów zostanie dodana do listy, więc jeśli zmodyfikujesz którykolwiek z nich, copyArrayofList również odzwierciedlają tę samą zmianę.
Jeśli nie chcesz efektu ubocznego, musisz skopiować każdy element z originalArrayList do copyArrayofList, tak jak przy użyciu pętli for lub while.
źródło
Oznacza to, że modyfikujesz listę podczas próby jej skopiowania, najprawdopodobniej w innym wątku. Aby to naprawić, musisz albo
użyj kolekcji, która jest przeznaczona do jednoczesnego dostępu.
odpowiednio zablokuj kolekcję, abyś mógł ją iterować (lub pozwól wywołać metodę, która zrobi to za Ciebie)
znajdź miejsce, aby uniknąć konieczności kopiowania oryginalnej listy.
źródło
Począwszy od Java 10 :
List.copyOf()
zwraca niemodyfikowalnyList
zawierający elementy danegoCollection
.Podane
Collection
nie może byćnull
i nie może zawierać żadnychnull
elementów.Ponadto, jeśli chcesz stworzyć głęboki kopii a
List
, można znaleźć wiele dobrych odpowiedzi tutaj .źródło
W Javie 8 jest jeszcze jedna metoda, która zapewnia zerową ochronę.
Jeśli chcesz pominąć jeden element.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList) .map(Collection::stream) .orElseGet(Stream::empty) .skip(1) .collect(Collectors.toList());
W przypadku języka Java 9+ można użyć metody strumieniowej Optional
źródło
Miałem ten sam problem ConcurrentAccessException i moim rozwiązaniem było:
List<SomeBean> tempList = new ArrayList<>(); for (CartItem item : prodList) { tempList.add(item); } prodList.clear(); prodList = new ArrayList<>(tempList);
Działa więc tylko jedną operację w tym samym czasie i pozwala uniknąć wyjątku ...
źródło
Próbowałem czegoś podobnego i udało mi się odtworzyć problem (IndexOutOfBoundsException). Poniżej moje ustalenia:
1) Implementacja Collections.copy (destList, sourceList) najpierw sprawdza rozmiar listy docelowej, wywołując metodę size (). Ponieważ wywołanie metody size () zawsze zwróci liczbę elementów na liście (w tym przypadku 0), konstruktor ArrayList (capacity) zapewnia tylko początkową pojemność tablicy zapasowej i nie ma to żadnego związku z wielkość listy. Dlatego zawsze otrzymujemy wyjątek IndexOutOfBoundsException.
2) Stosunkowo prostym sposobem jest użycie konstruktora, który jako argument przyjmuje kolekcję:
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);
źródło
Możesz użyć addAll ().
np .:
wsListCopy.addAll(wsList);
źródło
re
indexOutOfBoundsException
:, twoje argumenty podlisty są problemem; musisz zakończyć podlistę na rozmiarze-1. Będąc od zera, ostatni element listy ma zawsze rozmiar 1, nie ma elementu w pozycji rozmiaru, stąd błąd.źródło
Nie widzę poprawnej odpowiedzi. Jeśli chcesz uzyskać głęboką kopię, musisz ręcznie iterować i skopiować obiekt (możesz użyć konstruktora kopiującego).
źródło
Jeśli nie chcesz, aby zmiany na jednej liście wpływały na inną listę, spróbuj tego. Pomogło.
Mam nadzieję, że to pomoże.
public class MainClass { public static void main(String[] a) { List list = new ArrayList(); list.add("A"); List list2 = ((List) ((ArrayList) list).clone()); System.out.println(list); System.out.println(list2); list.clear(); System.out.println(list); System.out.println(list2); } } > Output: [A] [A] [] [A]
źródło
Funkcja subList to sztuczka, zwracany obiekt wciąż znajduje się na oryginalnej liście. więc jeśli wykonasz jakąkolwiek operację w subList, spowoduje to współbieżny wyjątek w kodzie, bez względu na to, czy jest to pojedynczy wątek, czy wiele wątków.
źródło