ทำไม Iterator ของ Java และ ListIterator ชี้ไปที่องค์ประกอบต่าง ๆ


9

Javadoc สำหรับ ListIteratorพูดว่า:

A ListIteratorไม่มีองค์ประกอบปัจจุบัน ตำแหน่งเคอร์เซอร์เสมออยู่ระหว่างองค์ประกอบที่จะถูกส่งกลับโดยเรียกร้องให้และองค์ประกอบที่จะถูกส่งกลับโดยเรียกร้องให้previous()next()

เหตุใด Java จึงถูกListIteratorนำไปใช้เพื่อชี้ให้เห็นองค์ประกอบระหว่างองค์ประกอบแทนที่จะเป็นองค์ประกอบปัจจุบัน มันดูเหมือนว่านี้จะทำให้รหัสลูกค้าสามารถอ่านได้น้อยลงเมื่อจะมีการเรียกซ้ำ ๆgetNext(), getPrevious()ดังนั้นผมถือว่าต้องมีเหตุผลที่ดีสำหรับการเลือก

ตามบันทึกข้างฉันเพียงแค่เขียนห้องสมุดเล็ก ๆ ที่เรียก peekable-arraylistที่ขยายArrayList, IteratorและListIteratorที่ให้peekAtNext()และpeekAtPrevious()วิธีการดำเนินการที่ชอบ:

  @Override public synchronized T peekAtNext() {
     T t = next();
     previous();
     return t;
  }

2
มีตัววนซ้ำที่มองเห็นได้ใน Guava library code.google.com/p/guava-l
kevin cline

ขอบคุณเควิน! ฉันโพสต์คำถามติดตามเรื่องนี้ใน SO: เป็นไปได้ไหมที่จะใช้ ForwardingListIterator ของ Guava กับ PeekingIterator
glenviewjeff

คำตอบ:


12

เท่าที่ฉันสามารถบอกได้เหตุผลสามารถพบได้ในส่วนของ javadoc ที่คุณไม่ได้อ้าง (เน้นที่ด้านล่างของฉัน):

ตัววนซ้ำสำหรับรายการที่อนุญาตให้โปรแกรมเมอร์ข้ามรายการในทิศทางใดทิศทางหนึ่งแก้ไขรายการในระหว่างการวนซ้ำ ...

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

ทีนี้ลองคิดดูว่าจะเกิดอะไรขึ้นถ้าเราลบองค์ประกอบที่จะเป็นตัวcurrent()วนซ้ำ - โดยสมมติว่าตัววนซ้ำนั้นมีความคิดเกี่ยวกับองค์ประกอบปัจจุบัน ในบริบทนี้วิธีการนำไปใช้โดยไม่มีความคิดเกี่ยวกับองค์ประกอบปัจจุบันทำให้ฉันรู้สึกดี - เนื่องจากวิธีนั้นตัววนซ้ำไม่ต้องกังวลเกี่ยวกับการลบองค์ประกอบ


เป็นสิ่งสำคัญที่ต้องทราบว่า javadoc ไม่ต้องการการปรับใช้อินเตอร์เฟสให้ปลอดภัยต่อเธรด

  • เพราะการที่หนึ่งไม่ควรคาดหวังว่าการจัดการที่ถูกต้องของการปรับเปลี่ยนทำจากหัวข้อที่แตกต่าง - สำหรับว่าการดำเนินการจะต้องมีการให้ความหมายเพิ่มเติมในการเข้าถึงประสานการมองเห็นการรับประกันอื่น ๆ ตามที่ระบุโดย Java หน่วยความจำรุ่นต่อJSR 133

ListIterator ใดที่สามารถจัดการการแก้ไขที่ทำจากเธรดเดียวกันเมื่อทำการวนซ้ำ ไม่ใช่ตัววนซ้ำทั้งหมดที่เป็นเช่นนั้นConcurrentModificationException javadocsเตือนเป็นพิเศษเกี่ยวกับสิ่งนี้:

... โปรดทราบว่าข้อยกเว้นนี้ไม่ได้บ่งชี้เสมอว่ามีการแก้ไขวัตถุในเวลาเดียวกันโดยเธรดอื่น หากเธรดเดี่ยวออกลำดับของการเรียกใช้เมธอดที่ละเมิดสัญญาของวัตถุวัตถุอาจโยนข้อยกเว้นนี้ ตัวอย่างเช่นหากเธรดแก้ไขคอลเล็กชันโดยตรงในขณะที่วนซ้ำคอลเลกชันด้วยตัววนซ้ำแบบล้มเหลวตัววนซ้ำจะส่งข้อยกเว้นนี้ ...


1
นอกจากนี้ยังหมายความว่าคุณไม่จำเป็นต้องแยกจากกันinsertBeforeและถึงแม้ว่ามันจะไม่ได้เป็นใหญ่เป็นปัญหาเป็นinsertAfter remove
Karl Bielefeldt

1
ดังนั้นปัญหาที่หนึ่งสามารถลบและเข้าถึงองค์ประกอบปัจจุบันพร้อมกันได้หรือไม่ สิ่งนี้จะไม่เป็นปัญหาที่เทียบเท่ากับการโทรพร้อมกันnext()หรือไม่ remove()จะเป็นจะsynchronized getCurrent()ฉันพลาดอะไรไปรึเปล่า?
glenviewjeff

@glenviewjeff นั่นเป็นข้อสังเกตที่ดีมาก ฉันยังสงสัยว่าจะจัดการกับ CME ได้อย่างไร - ความตั้งใจดังกล่าวเพื่ออนุญาตให้มีการแก้ไขทำให้เกิดความกังวลเช่นนั้น เดาว่าฉันต้องขุดให้ลึก ฉัน 99.99% แน่ใจว่ามันไม่ได้มีเจตนาเป็นที่ปลอดภัยด้ายบางทีมันอาจจะสามารถจัดการวัยรุ่นพร้อมกันทำได้จากหัวข้อเดียวกัน (ไม่ iterators ทุกคนมีความสามารถในการที่คุณจะรู้)
ริ้น

หากคุณสนใจดูการแก้ไขของฉัน ฉันใช้และจัดทำส่วนขยายArrayListเพื่อทำสิ่งนี้ให้สำเร็จ
glenviewjeff

@glenviewjeff ที่น่าสนใจ ในการติดตั้งของคุณถัดไป () และก่อนหน้านี้ () ซิงค์กันไหม ฉันถามเพราะถ้าไม่แล้วหัวข้ออื่น ๆ สามารถ "เจาะ" การย้ายที่ไม่คาดคิดบางอย่างตรงกลางของคุณปัจจุบัน () ทำให้พฤติกรรมไม่เหมือนลูกค้าคาดหวังว่า ... วิธีการเช่นเพิ่ม () อาจจะต้องซิงค์ด้วย
gnat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.