Java.util.List'i başka bir java.util.List'e kopyalama


136

Bir var List<SomeBean>bir Web hizmetinden doldurulur söyledi. Bu listenin içeriğini aynı türden boş bir listeye kopyalamak / klonlamak istiyorum. Bir listeyi kopyalamak için bir Google araması Collections.copy()yöntemi kullanmamı önerdi . Gördüğüm tüm örneklerde, hedef listesinin kopyalamanın gerçekleşmesi için tam sayıda öğe içermesi gerekiyordu.

Kullandığım liste bir web servisi aracılığıyla doldurulduğu ve yüzlerce nesne içerdiği için yukarıdaki tekniği kullanamıyorum. Yoksa yanlış kullanıyorum ?? !! Her neyse, işe yaraması için böyle bir şey yapmaya çalıştım ama hala bir IndexOutOfBoundsException.

List<SomeBean> wsList = app.allInOne(template);

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());   
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());

Kullanmaya çalıştım wsListCopy=wsList.subList(0, wsList.size())ama ConcurrentAccessExceptionkodda daha sonra var . Vur ve deneme. :)

Her neyse, sorum basit, listemin tüm içeriğini başka bir Listeye nasıl kopyalayabilirim? Elbette yineleme yoluyla değil.


11
Herhangi bir kopya elbette yinelemeyi kullanacaktır. Onu saklayabilirsin ama o yine de orada olacak.
Peter Lawrey

1
Her şeyden önce: bu listeyi kopyalaman gerektiğine emin misin? Bunu yapmaktaki motivasyonunuz nedir?
ppeterka

2
Evet, yineleme sadece bu katmanların altında gizlidir. Ancak, herhangi bir yineleme yanıtını önlemek için yorum eklendi. :)
Mono Jamoon

@ppeterka Listede removeAll () gibi işlemler yapıyorum. Bu, listenin orijinal verilerini kaybetmesine neden olur. Ve daha sonra "o veri" de gereklidir.
Mono Jamoon

Geri dönen bir listenin asıl türü nedir app.allInOne(template)? ArrayList?
Andremoniy

Yanıtlar:


235

Sadece şunu kullan:

List<SomeBean> newList = new ArrayList<SomeBean>(otherList);

Not: Hala iş parçacığı güvenli değil otherList, başka bir iş parçacığından değişiklik yaparsanız , o zaman bunu otherList(ve hatta newList) a yapmak isteyebilirsiniz CopyOnWriteArrayList- veya her listeye okuma / yazma erişimini serileştirmek için ReentrantReadWriteLock gibi bir ilkel kilit kullanmak isteyebilirsiniz . eşzamanlı olarak erişildi.


1
Şimdi, kendimi gerçekten aptal gibi hissediyorum :) Umarım bu şekilde inşa etmenin bir anlamı olmaz ConcurrentAccessException.
Mono Jamoon


5
ConcurrentModifcationException alıyorsa +1, önce düzeltmesi gereken bir eşzamanlılık sorunu var.
Peter Lawrey

5
Soru "kopyala / klonla" dan bahsediliyorsa bu yanıt neden bu kadar çok puan alıyor? Bu, diğer bazı cevapların klonlamayla ilgisi olmadığı sürece. Aynı referanslar, kullandığınız koleksiyona / akışa özgü faydalı yöntemlere bakılmaksızın, koleksiyonların içindeki nesneler için saklanacaktır.
yuranos

3
Cevap yanlış. İçerik kopyalanmaz. Sadece referanslarıdır.
inanılmaz

33

Bu, Java 8'in gerçekten güzel bir yoludur:

List<String> list2 = list1.stream().collect(Collectors.toList());

Elbette buradaki avantaj, listenin yalnızca bir kısmını filtreleyip atlayabilmenizdir.

Örneğin

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());

4
ortaya çıkan liste orijinal listenin derin kopyası mı yoksa basit bir kopyası mı?
Ad Infinitum

7
Sığ bir kopya.
kap

3
Ne yazık ki bu da iş parçacığı için güvenli değil. listToplayıcı çalışırken değiştiğini varsayarsak , a ConcurrentModificationExceptionatılır.
C-Otto

@Dan, Son elemanı kopyalamak nasıl atlanır?
CKM

@chandresh son öğeyi kopyalamayı atlamak için kullanmalısınız.limit(list1.size() - 1)
Matthew Carpenter

13
originalArrayList.addAll(copyArrayofList);

Lütfen, copy için addAll () yöntemini her kullandığınızda, aynı nesnelere yönelik her iki dizi listesinin (originalArrayList ve copyArrayofList) içeriğinin listeye ekleneceğini unutmayın; bu nedenle, bunlardan herhangi birini değiştirirseniz copyArrayofList de aynı değişikliği yansıtır.

Eğer yan etki istemiyorsanız, for veya while döngüsü kullanmak gibi her bir öğeyi originalArrayList'ten copyArrayofList'e kopyalamanız gerekir.


2
Bu, #addAll'ın sığ bir kopya oluşturmasının yanı sıra nasıl derin kopyalama yapılacağını belirttiği için buradaki birkaç gerçek Cevaptan biridir. Daha fazla ayrıntı: stackoverflow.com/questions/715650/…
cellepo

7

Bunun gibi bir şey yapmayı denedim, ancak yine de IndexOutOfBoundsException aldım.

ConcurrentAccessException aldım

Bu, kopyalamaya çalışırken, büyük olasılıkla başka bir iş parçacığında listeyi değiştirdiğiniz anlamına gelir. Bunu düzeltmek için ya

  • eşzamanlı erişim için tasarlanmış bir koleksiyon kullanın.

  • Koleksiyonu uygun şekilde kilitleyin, böylece üzerinde yineleme yapabilirsiniz (veya bunu sizin için yapan bir yöntemi çağırmanıza izin verin)

  • orijinal listeyi kopyalamak zorunda kalmamak için bir uzakta bulun.


4

Java 10'dan başlayarak :

List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);

List.copyOf()Listverilen öğenin öğelerini içeren bir değiştirilemez döndürür Collection.

Verilenler Collectionolmamalı nullve herhangi bir nullunsur içermemelidir .

Ayrıca, a'nın derin bir kopyasını oluşturmak Lististiyorsanız, burada birçok iyi yanıt bulabilirsiniz .


3

Boş güvenlikli bir şekilde Java 8 ile başka bir yöntem daha var.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .collect(Collectors.toList());

Bir öğeyi atlamak istiyorsanız.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .skip(1)
    .collect(Collectors.toList());

Java 9+ ile İsteğe Bağlı akış yöntemi kullanılabilir

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())

1

ConcurrentAccessException ile aynı sorunu yaşıyordum ve mysolution şuydu:

List<SomeBean> tempList = new ArrayList<>();

for (CartItem item : prodList) {
  tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);

Yani bir seferde sadece bir işlem yapar ve Muafiyetten kaçınır ...


1

Benzer bir şey denedim ve sorunu yeniden oluşturabildim (IndexOutOfBoundsException). Bulgularım aşağıdadır:

1) Collections.copy'nin (destList, sourceList) uygulanması önce size () yöntemini çağırarak hedef listenin boyutunu kontrol eder. Size () yöntemine yapılan çağrı her zaman listedeki öğelerin sayısını (bu durumda 0) döndüreceğinden, yapıcı ArrayList (kapasite) yalnızca arka dizinin başlangıç ​​kapasitesini sağlar ve bunun, listenin boyutu. Bu nedenle her zaman IndexOutOfBoundsException alıyoruz.

2) Nispeten basit bir yol, bir koleksiyonu bağımsız değişken olarak alan yapıcıyı kullanmaktır:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  

0

re:, alt indexOutOfBoundsExceptionliste argümanlarınız problemdir; alt listeyi-1 boyutunda sonlandırmanız gerekir. Sıfır tabanlı olduğundan, listenin son öğesi her zaman boyut-1'dir, boyut konumunda hiçbir öğe yoktur, dolayısıyla hata.




-2

Bir listedeki değişikliklerin başka bir listeyi etkilemesini istemiyorsanız bunu deneyin.Benim için çalıştı
Umarım bu yardımcı olur.

  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]

-3

subList işlevi bir hiledir, döndürülen nesne hala orijinal listededir. bu nedenle, subList içinde herhangi bir işlem yaparsanız, tek iş parçacıklı veya çok iş parçacıklı olursa olsun, kodunuzda eşzamanlı istisnaya neden olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.