วิธีคัดลอก java.util.List ไปยัง java.util.List อื่น


140

ฉันมีข้อมูลList<SomeBean>ที่สร้างขึ้นจากบริการบนเว็บ ฉันต้องการคัดลอก / โคลนเนื้อหาของรายการนั้นลงในรายการว่างประเภทเดียวกัน การค้นหาโดย Google สำหรับการคัดลอกรายการแนะนำให้ฉันใช้Collections.copy()วิธีการ ในตัวอย่างทั้งหมดที่ฉันเห็นรายการปลายทางควรมีจำนวนรายการที่แน่นอนเพื่อให้การคัดลอกเกิดขึ้น

เนื่องจากรายการที่ฉันใช้มีการเติมข้อมูลผ่านบริการเว็บและมีวัตถุหลายร้อยรายการฉันจึงไม่สามารถใช้เทคนิคข้างต้นได้ หรือผมใช้ผิด ?? !! อย่างไรก็ตามเพื่อให้ได้ผลฉันพยายามทำอะไรแบบนี้ แต่ฉันก็ยังได้IndexOutOfBoundsExceptionไฟล์.

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

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

ฉันพยายามใช้wsListCopy=wsList.subList(0, wsList.size())แต่ฉันได้รับConcurrentAccessExceptionรหัสในภายหลัง ตีและทดลองใช้ :)

อย่างไรก็ตามคำถามของฉันง่ายมากฉันจะคัดลอกเนื้อหาทั้งหมดในรายการของฉันไปยังรายการอื่นได้อย่างไร ไม่ผ่านการย้ำแน่นอน


11
สำเนาใด ๆ จะใช้การทำซ้ำแน่นอน คุณสามารถซ่อนมันได้ แต่มันจะยังคงอยู่ที่นั่น
Peter Lawrey

1
ก่อนอื่นคุณแน่ใจหรือว่าต้องคัดลอกรายการนั้น อะไรคือแรงจูงใจของคุณในการทำเช่นนั้น?
ppeterka

2
ใช่การทำซ้ำซ่อนอยู่ใต้เลเยอร์นั้น แต่มีการเพิ่มความคิดเห็นเพื่อป้องกันการตอบซ้ำ :)
Mono Jamoon

@ppeterka ฉันกำลังดำเนินการในรายการเช่น removeAll () สิ่งนี้ทำให้รายการสูญเสียข้อมูลดั้งเดิม และ "ข้อมูลนั้น" จะต้องใช้ในภายหลังด้วย
Mono Jamoon

ประเภทของรายการที่ส่งคืนโดยแท้จริงคือapp.allInOne(template)อะไร? ArrayListเหรอ?
Andremoniy

คำตอบ:


240

เพียงใช้สิ่งนี้:

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

หมายเหตุ: ยังไม่ปลอดภัยสำหรับเธรดหากคุณแก้ไขotherListจากเธรดอื่นคุณอาจต้องการสร้างสิ่งนั้นotherList(และแม้กระทั่งnewList) CopyOnWriteArrayListตัวอย่างเช่น - หรือใช้แบบดั้งเดิมของการล็อกเช่นReentrantReadWriteLockเพื่อจัดลำดับการเข้าถึงการอ่าน / เขียนรายการใด ๆ เข้าถึงพร้อมกัน


1
ตอนนี้ฉันรู้สึกโง่จริงๆ :) ฉันหวังว่าการสร้างแบบนี้จะไม่ทำให้เกิดความConcurrentAccessExceptionเสียหายใด ๆ
Mono Jamoon


5
+1 หากเขาได้รับ ConcurrentModifcationException แสดงว่าเขามีปัญหาการทำงานพร้อมกันที่ต้องแก้ไขก่อน
Peter Lawrey

6
เหตุใดคำตอบนี้จึงได้รับคะแนนมากมายหากคำถามกล่าวถึง "copy / clone"? สิ่งนี้ตราบใดที่คำตอบอื่น ๆ ไม่เกี่ยวข้องกับการโคลน การอ้างอิงเดียวกันนี้จะถูกเก็บไว้สำหรับอ็อบเจ็กต์ภายในคอลเลคชันไม่ว่าคุณจะใช้วิธียูทิลิตีคอลเลกชัน / สตรีม
yuranos

3
คำตอบคือผิด ไม่ได้คัดลอกเนื้อหา เป็นข้อมูลอ้างอิงเท่านั้น
เหลือเชื่อ

34

นี่เป็นวิธีที่ดีมากสำหรับ Java 8:

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

แน่นอนข้อดีคือคุณสามารถกรองและข้ามไปที่สำเนาเฉพาะบางส่วนของรายการได้

เช่น

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

4
รายการผลลัพธ์เป็นสำเนาลึกหรือสำเนาตื้นของรายการต้นฉบับหรือไม่
Ad Infinitum

7
สำเนาตื้น
kap

3
สิ่งนี้น่าเศร้าที่ยังไม่ปลอดภัยต่อเธรด สมมติว่าlistมีการเปลี่ยนแปลงในขณะที่ตัวสะสมกำลังทำงานConcurrentModificationExceptionอยู่จะถูกโยนทิ้ง
C-Otto

@ แดนวิธีการข้ามการคัดลอกองค์ประกอบสุดท้าย?
CKM

@chandresh หากต้องการข้ามการคัดลอกองค์ประกอบสุดท้ายคุณจะใช้.limit(list1.size() - 1)
Matthew Carpenter

14
originalArrayList.addAll(copyArrayofList);

โปรดจำไว้ว่าเมื่อใดก็ตามที่ใช้เมธอดaddAll () ในการคัดลอกเนื้อหาของรายการอาร์เรย์ทั้งสอง (originalArrayList และ copyArrayofList) การอ้างอิงถึงวัตถุเดียวกันจะถูกเพิ่มเข้าไปในรายการดังนั้นหากคุณแก้ไขรายการใดรายการหนึ่งจากนั้น copyArrayofList ด้วย สะท้อนให้เห็นถึงการเปลี่ยนแปลงเดียวกัน

หากคุณไม่ต้องการผลข้างเคียงคุณจะต้องคัดลอกแต่ละองค์ประกอบจาก originalArrayList ไปยัง copyArrayofList เช่นใช้ for or while loop


2
นี่เป็นหนึ่งในคำตอบที่แท้จริงเพียงไม่กี่คำที่นี่เนื่องจากระบุว่า #addAll ทำสำเนาแบบตื้นรวมถึงวิธีการคัดลอกแบบลึก รายละเอียดเพิ่มเติม: stackoverflow.com/questions/715650/…
cellepo

7

ฉันพยายามทำอะไรแบบนี้ แต่ฉันยังได้รับ IndexOutOfBoundsException

ฉันได้รับ ConcurrentAccessException

ซึ่งหมายความว่าคุณกำลังแก้ไขรายการในขณะที่คุณพยายามคัดลอกซึ่งส่วนใหญ่จะอยู่ในชุดข้อความอื่น ในการแก้ไขปัญหานี้คุณต้องทำอย่างใดอย่างหนึ่ง

  • ใช้คอลเล็กชันที่ออกแบบมาสำหรับการเข้าถึงพร้อมกัน

  • ล็อคคอลเลกชันอย่างเหมาะสมเพื่อให้คุณสามารถทำซ้ำได้ (หรืออนุญาตให้คุณเรียกวิธีการที่ทำสิ่งนี้ให้คุณ)

  • หาที่อยู่ห่างออกไปเพื่อหลีกเลี่ยงความจำเป็นในการคัดลอกรายการต้นฉบับ


4

เริ่มจากJava 10 :

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

List.copyOf()ส่งกลับ unmodifiable ที่มีองค์ประกอบของที่กำหนดListCollection

ที่กำหนดCollectionจะต้องไม่เป็นnullและต้องไม่มีnullองค์ประกอบใด ๆ

นอกจากนี้ถ้าคุณต้องการที่จะสร้างสำเนาลึกของListคุณสามารถหาคำตอบที่ดีมากที่นี่


3

มีวิธีอื่นกับ Java 8 ในวิธีที่ปลอดภัย

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

หากคุณต้องการข้ามองค์ประกอบหนึ่ง

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

ด้วย Java 9+ สามารถใช้วิธีการสตรีมของตัวเลือกได้

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

1

ฉันมีปัญหาเดียวกัน ConcurrentAccessExceptionและ mysolution คือ:

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

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

ดังนั้นจึงใช้งานได้เพียงครั้งเดียวในขณะนั้นและหลีกเลี่ยงการ Exeption ...


1

ฉันลองสิ่งที่คล้ายกันและสามารถสร้างปัญหาซ้ำได้ (IndexOutOfBoundsException) ด้านล่างนี้เป็นการค้นพบของฉัน:

1) การใช้งาน Collections.copy (destList, sourceList) ขั้นแรกให้ตรวจสอบขนาดของรายการปลายทางโดยเรียกเมธอด size () เนื่องจากวิธีการเรียกใช้ size () จะส่งกลับจำนวนองค์ประกอบในรายการเสมอ (0 ในกรณีนี้) ArrayList ตัวสร้าง (ความจุ) จึงมั่นใจได้เฉพาะความจุเริ่มต้นของอาร์เรย์สำรองและสิ่งนี้ไม่มีความสัมพันธ์ใด ๆ กับ ขนาดของรายการ ดังนั้นเราจึงมักจะได้รับ IndexOutOfBoundsException

2) วิธีที่ค่อนข้างง่ายคือการใช้ตัวสร้างที่ใช้คอลเลกชันเป็นอาร์กิวเมนต์:

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


0

re: indexOutOfBoundsExceptionรายการย่อยของคุณมีปัญหา คุณต้องจบรายการย่อยที่ size-1 เนื่องจากเป็นศูนย์องค์ประกอบสุดท้ายของรายการคือขนาด -1 เสมอไม่มีองค์ประกอบในตำแหน่งขนาดดังนั้นข้อผิดพลาด


0

ฉันไม่เห็นคำตอบที่ถูกต้อง หากคุณต้องการสำเนาลึกคุณต้องวนซ้ำและคัดลอกวัตถุด้วยตนเอง (คุณสามารถใช้ตัวสร้างสำเนา)


นี่เป็นหนึ่งในคำตอบที่แท้จริงเพียงไม่กี่คำที่นี่ รายละเอียดเพิ่มเติม: stackoverflow.com/questions/715650/…
cellepo

-2

หากคุณไม่ต้องการให้การเปลี่ยนแปลงในรายการหนึ่งมีผลกับรายการอื่นให้ลองทำเช่นนี้มันได้ผลสำหรับฉัน
หวังว่านี่จะช่วยได้

  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 เป็นเคล็ดลับวัตถุที่ส่งคืนยังคงอยู่ในรายการเดิม ดังนั้นหากคุณดำเนินการใด ๆ ในรายการย่อยจะทำให้เกิดข้อยกเว้นพร้อมกันในโค้ดของคุณไม่ว่าจะเป็นเธรดเดียวหรือเธรดหลายเธรด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.