ConcurrentModificationException
ผมขอให้ตัวอย่างบางส่วนที่มีทางเลือกบางอย่างที่จะหลีกเลี่ยง
สมมติว่าเรามีคอลเล็กชันหนังสือดังต่อไปนี้
List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));
รวบรวมและลบ
เทคนิคแรกประกอบด้วยการรวบรวมวัตถุทั้งหมดที่เราต้องการลบ (เช่นการใช้ขั้นสูงสำหรับการวนซ้ำ) และหลังจากที่เราทำการวนซ้ำเสร็จสิ้นเราจะลบวัตถุที่พบทั้งหมด
ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
นี่เป็นการสมมติว่าการดำเนินการที่คุณต้องการทำคือ "ลบ"
หากคุณต้องการที่จะ "เพิ่ม" วิธีการนี้จะใช้งานได้ แต่ฉันคิดว่าคุณจะวนซ้ำคอลเล็กชันอื่นเพื่อพิจารณาว่าคุณต้องการเพิ่มองค์ประกอบใดลงในคอลเล็กชันที่สองจากนั้นจึงออกaddAll
วิธีในตอนท้าย
ใช้ ListIterator
หากคุณกำลังทำงานกับรายการเทคนิคอื่นประกอบด้วยการใช้ListIterator
ที่มีการสนับสนุนสำหรับการลบและการเพิ่มรายการในระหว่างการทำซ้ำตัวเอง
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
อีกครั้งฉันใช้วิธี "ลบ" ในตัวอย่างด้านบนซึ่งเป็นคำถามของคุณที่ดูเหมือนจะบอกเป็นนัย แต่คุณอาจใช้add
วิธีนี้เพื่อเพิ่มองค์ประกอบใหม่ในระหว่างการทำซ้ำ
ใช้ JDK> = 8
สำหรับผู้ที่ทำงานกับ Java 8 หรือรุ่นที่เหนือกว่ามีเทคนิคอื่น ๆ ที่คุณสามารถใช้เพื่อใช้ประโยชน์จากมัน
คุณสามารถใช้removeIf
วิธีการใหม่ในCollection
ชั้นฐาน:
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
หรือใช้ API สตรีมใหม่:
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
ในกรณีสุดท้ายนี้ในการกรององค์ประกอบออกจากคอลเลกชันคุณมอบหมายการอ้างอิงดั้งเดิมไปยังคอลเลกชันที่กรอง (เช่นbooks = filtered
) หรือใช้คอลเลกชันที่กรองไปremoveAll
ยังองค์ประกอบที่พบจากคอลเลกชันดั้งเดิม (เช่นbooks.removeAll(filtered)
)
ใช้รายการย่อยหรือกลุ่มย่อย
มีทางเลือกอื่น ๆ เช่นกัน หากรายการถูกเรียงลำดับและคุณต้องการลบองค์ประกอบที่ต่อเนื่องกันคุณสามารถสร้างรายการย่อยแล้วล้างมัน:
books.subList(0,5).clear();
เนื่องจากรายการย่อยได้รับการสนับสนุนโดยรายการดั้งเดิมจึงเป็นวิธีที่มีประสิทธิภาพในการลบองค์ประกอบย่อยขององค์ประกอบนี้
สิ่งที่คล้ายกันสามารถทำได้ด้วยชุดเรียงที่ใช้NavigableSet.subSet
วิธีการหรือวิธีการใด ๆ ที่มีการเสนอ
การพิจารณา:
วิธีการที่คุณใช้อาจขึ้นอยู่กับสิ่งที่คุณตั้งใจจะทำ
- การรวบรวมและ
removeAl
เทคนิคทำงานกับการรวบรวม (การรวบรวมรายการการตั้งค่า ฯลฯ )
ListIterator
เทคนิคการทำงานอย่างเห็นได้ชัดเท่านั้นที่มีรายชื่อให้ว่าพวกเขาได้รับListIterator
ข้อเสนอการดำเนินการสนับสนุนสำหรับการเพิ่มและลบการดำเนินงาน
Iterator
วิธีการจะทำงานร่วมกับชนิดของคอลเลกชันใด ๆ แต่จะสนับสนุนเฉพาะการดำเนินงานลบ
- ด้วยวิธี
ListIterator
/ Iterator
ข้อดีที่ชัดเจนคือไม่ต้องคัดลอกอะไรเลยตั้งแต่เราลบเมื่อเราย้ำ ดังนั้นนี้มีประสิทธิภาพมาก
- ตัวอย่างสตรีม JDK 8 ไม่ได้ลบอะไรจริงๆ แต่มองหาองค์ประกอบที่ต้องการจากนั้นเราแทนที่การอ้างอิงคอลเลกชันดั้งเดิมด้วยอันใหม่และให้อันเก่าเก็บขยะ ดังนั้นเราจึงย้ำเพียงครั้งเดียวในการรวบรวมและจะมีประสิทธิภาพ
- ในการรวบรวมและ
removeAll
เข้าใกล้ข้อเสียคือเราต้องย้ำสองครั้ง อันดับแรกเราวนซ้ำในวง foor-loop มองหาวัตถุที่ตรงกับเกณฑ์การเอาออกของเราและเมื่อเราพบแล้วเราขอให้ลบออกจากคอลเลกชันดั้งเดิม ย้ายมัน.
- ฉันคิดว่าเป็นมูลค่าการกล่าวขวัญว่าวิธีการลบของ
Iterator
อินเตอร์เฟซที่ถูกทำเครื่องหมายเป็น "ตัวเลือก" ใน Javadocs ซึ่งหมายความว่าอาจมีIterator
การใช้งานที่โยนUnsupportedOperationException
ถ้าเราเรียกใช้วิธีการลบ ดังนั้นฉันจึงบอกว่าวิธีนี้ปลอดภัยน้อยกว่าวิธีอื่นถ้าเราไม่สามารถรับประกันการสนับสนุนตัววนซ้ำสำหรับการลบองค์ประกอบ