การ遍历 ArrayList
แนะนำใหม่| English | ความหมาย |
|---|---|
| ConcurrentModificationException/kənˈkʌrənt ˌmɒdɪfɪˈkeɪʃn ekˈsepʃn/ | ConcurrentModificationException |
เลือกการ遍历ที่ ให้ตรงกับการเปลี่ยนแปลงที่ตั้งใจไว้
- An ArrayList มี [2, 3, 4]. คุณต้องการคูณสองทุกค่าที่จัดเก็บไว้ โดยยังคงจำนวนองค์ประกอบไว้เท่าเดิม
- Indexed loop สามารถใช้ list.set(i, 2 * list.get(i)). การกำหนด x = 2*x ใน for (int x : list) เปลี่ยนเฉพาะตัวแปรลูปในท้องถิ่นเท่านั้น
เริ่มต้นจากรายการ [2, 3, 4], รัน for (int x : list) { x = 2 * x; }. list.get(1) คืออะไร?
ความยาก 2/5 · 140 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
การกำหนดค่า local primitive x ไม่สามารถแทนที่ Integer ที่จัดเก็บได้ องค์ประกอบตรงกลางของรายการยังคงเป็น 3
การวนลูปผ่านรายการ
- Traverse ArrayList เหมือนกับ array แต่ใช้วิธีการของมัน Indexed:
for (int i = 0; i < list.size(); i++) { ... list.get(i) ... } - For-each:
for (String s : list) { ... s ... }— เหมาะสำหรับการอ่านค่าsize()(ไม่ใช่length) เพื่อจำกัดขอบเขตของลูปแบบใช้ดัชนี
รูปแบบเดียวกันนี้
- การรวมผลนับจำนวน ค่าต่ำสุด/สูงสุด และการค้นหา ทำงานเหมือนกับอาร์เรย์ ให้เปลี่ยน
a[i]เป็นlist.get(i)และa.lengthเป็นlist.size()แทน - การสะสมและตรรกะการนับ/หาค่าสูงสุดเหมือนกันทุกประการ สิ่งที่คุณเรียนรู้เกี่ยวกับการวนผ่านอาร์เรย์สามารถนำไปใช้ได้ทันที
การอ่านและการแก้ไข
- ลูปที่ปรับปรุงแล้วจะคัดลอกค่าของแต่ละองค์ประกอบเข้าไปในตัวแปรของลูป สำหรับ
Integerที่อ่านเป็นint xแล้วการกำหนดค่าให้xจะไม่แทนที่องค์ประกอบในลิสต์ แต่ลูปแบบใช้ดัชนีสามารถแทนที่它以set(i, x)ได้ - สำหรับการเปลี่ยนแปลงโครงสร้าง (เพิ่ม/ลบ) ให้ใช้ลูปแบบใช้ดัชนีด้วยความระมัดระวัง การอ่านทำได้ง่าย แต่การลบขณะวนลูปต้องระวังเป็นพิเศษ (ในบทเรียนถัดไป)
การรวมค่าArrayListตาม index
Bound with size(), read with get(i) (list = [10,20,30])
เงื่อนไขที่ถูกต้องสำหรับIndexed loop ของ ArrayList คือ...
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
ArrayList ใช้ size(); arrays ใช้ length
Why should a program avoid direct structural changes during an ArrayList enhanced-for traversal?
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
ArrayList fail-fast behaviour is best-effort. Avoid unsafe traversal rather than relying on a guaranteed exception.
รูปแบบการ遍历 array (sum, count, max) ทำงานเหมือนกันสำหรับ ArrayList
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
เพียงสลับ a[i]/a.length เป็น list.get(i)/list.size()
เพื่อลบองค์ประกอบอย่างปลอดภัยขณะ遍历ลิสต์ คุณควรใช้...
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
for-each ไม่สามารถแก้ไขโครงสร้างได้; indexed loop สามารถ (ด้วยความระมัดระวัง)
โดยไม่มีการแก้ไขโครงสร้างระหว่างการทำซ้ำ Enhanced loop สามารถอ่านข้อมูลทั้งหมดของ ArrayList
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
ลูปนี้จะอ่านอ้างอิงที่เก็บไว้แต่ละตัว การเปลี่ยนแปลงโครงสร้างระหว่างการทำซ้ำเป็นเรื่องแยกต่างหาก; ข้อความนี้ไม่รับประกันว่าทุกการดำเนินการบนองค์ประกอบที่เป็นไปได้ทั้งหมดจะปลอดภัย
อย่าแก้ไขข้อมูลระหว่างสำหรับ-แต่ละ
- การเพิ่มหรือลบ ระหว่าง for-each loop อาจทำให้เกิด ConcurrentModificationException; ระบบตรวจจับ fail-fast ทำได้เพียงดีที่สุด For-each loop สมมติว่าลิสต์ไม่มีการเปลี่ยนแปลงโครงสร้างอยู่เบื้องหลัง
- เพื่อลบขณะ traversing, ใช้ indexed loop (และจัดการ index). อ่านด้วย for-each เหมาะสมเมื่อรายการไม่ถูกเปลี่ยนแปลงโครงสร้างระหว่าง traversing. ตรวจสอบข้อกำหนดของ element ด้วย: unboxing null Integer ยังโยน exception
จำกัดขอบเขตของ Indexed ArrayList loop ด้วย list.size(), ไม่ใช่ .length, และห้ามแก้ไขโครงสร้างข้อมูลระหว่าง For-each การเรียก add/remove ภายใน for (x : list) อาจทำให้เกิด ConcurrentModificationException (ข้อยกเว้นการแก้ไขขณะวนซ้ำ), แต่การตรวจจับไม่ได้รับประกันเสมอ หากต้องการลบข้อมูลขณะวน遍历 ให้ใช้ Indexed loop — และจำไว้ว่า remove(i) จะเลื่อนองค์ประกอบอื่นไปข้างหลัง, อย่า i++ ผ่านองค์ประกอบที่ถูกเลื่อนไปโดยไม่คิด
After the indexed doubling update, what is list.get(1)?
ความยาก 2/5 · 140 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
The middle stored value 3 is replaced by 6. Reassigning a primitive loop variable would leave it at 3.
สำหรับ Student entries ที่ไม่ใช่ null, s.addScore(5) ภายใน for (Student s : students) สามารถเปลี่ยน Students ที่จัดเก็บได้โดยไม่ต้องเพิ่มหรือลบองค์ประกอบในรายการ
ความยาก 1/5 · 100 เหรียญ + โบนัสเล็กน้อยในการทำครั้งแรกวันนี้
อ้างอิงที่คัดลอกจะเข้าถึงวัตถุ Student ที่สามารถแก้ไขได้ฟิลด์ของพวกเขาสามารถเปลี่ยนแปลงได้โดยไม่ทำให้โครงสร้างรายการเปลี่ยนไป
Summing an ArrayList
- Indexed:
for (int i = 0; i < list.size(); i++) { sum += list.get(i); } - For-each:
for (int x : list) { sum += x; }(autoboxing/unboxing จัดการ Integer↔int) - ทั้งสองวิธีรวมรายการ; for-each สะอาดกว่าสำหรับ read-only
ขยายเหตุผลไปยังกรณีใหม่
- การเพิ่มหรือลบโดยตรงระหว่างการวนซ้ำแบบปรับปรุงนั้นไม่ปลอดภัย; ข้อยกเว้น fail-fast ทำได้เพียงดีที่สุด ไม่ใช่การตรวจสอบความถูกต้องที่รับประกัน
- รายการที่มี Student Objects แบบ mutable สามารถวนผ่านด้วย
for (Student s : students) { s.addScore(5); }โดยสมมติว่ามีข้อมูลที่ไม่ใช่ null การนี้จะเปลี่ยนแปลงสถานะของแต่ละวัตถุโดยไม่เปลี่ยนโครงสร้างรายการ; การกำหนด reference ใหม่ให้sจะไม่แทนที่องค์ประกอบที่จัดเก็บไว้
Traverse一个ArrayList ด้วยindexed loop (i < list.size(), list.get(i)) หรือ enhanced loop ที่รับแต่ละ element value. Array patterns (sum, count, min/max, search) ทั้งหมดถูก transfer过来. หลีกเลี่ยงการเปลี่ยนแปลงโครงสร้างโดยตรงระหว่าง enhanced traversal: ConcurrentModificationException อาจ detect ความผิดพลาด, แต่ไม่ได้รับประกัน. ใช้ carefully managed indexed loop สำหรับ removal pattern ที่สอนถัดไป; การเปลี่ยน fields ของ object ที่ reference เป็นสิ่งต่างจากการเปลี่ยน list structure