1. ความเป็นมาเกี่ยวกับวิธีการวนซ้ำ
คุณคุ้นเคยHashSetกับ หากคุณได้ศึกษามันจริงๆ นอกเหนือจากการอ่านบทเรียนแล้ว คุณควรถามคำถามนี้:
ฉันจะแสดงรายการองค์ประกอบ HashSet ทั้งหมดบนหน้าจอได้อย่างไร ท้ายที่สุดไม่มีอินเทอร์เฟซget()และset()วิธีการ!
และHashSetไม่ได้อยู่คนเดียวในข้อจำกัดนี้ นอกจากนี้ ยังHashSetมีคอลเล็กชันอื่นๆ อีกมากมายที่ไม่อนุญาตให้ดึงองค์ประกอบโดยดัชนี เนื่องจากองค์ประกอบไม่มีลำดับที่กำหนดไว้
ในช่วงหลายปีที่ผ่านมา โปรแกรมเมอร์ได้คิดค้นโครงสร้างข้อมูลที่ซับซ้อนมากมาย เช่น กราฟและต้นไม้ หรือรายการของรายการ.
คอนเทนเนอร์จำนวนมากเปลี่ยนลำดับขององค์ประกอบเมื่อมีการเพิ่มองค์ประกอบใหม่หรือนำองค์ประกอบที่มีอยู่ออก ตัวอย่างเช่น รายการจัดเก็บองค์ประกอบในลำดับเฉพาะ และเมื่อมีการเพิ่มองค์ประกอบใหม่ องค์ประกอบนั้นจะถูกแทรกไว้กลางรายการเกือบตลอดเวลา
และเรายังได้รับสถานการณ์ที่มีคอนเทนเนอร์ที่เก็บองค์ประกอบ แต่ไม่ได้อยู่ในลำดับที่ตายตัว
สมมติว่าเราต้องการคัดลอกองค์ประกอบทั้งหมดจากคอลเลกชันดังกล่าวไปยังอาร์เรย์หรือรายการ เราต้องได้รับองค์ประกอบทั้งหมด เราไม่สนใจลำดับที่เราวนซ้ำองค์ประกอบต่างๆ สิ่งสำคัญคืออย่าวนซ้ำองค์ประกอบเดียวกันมากกว่าหนึ่งครั้ง เราจะทำอย่างนั้นได้อย่างไร?
2. Iterator สำหรับคอลเลกชัน
Iteratorsถูกเสนอเป็นวิธีแก้ปัญหาข้างต้น
ตัววนซ้ำเป็นวัตถุพิเศษที่เกี่ยวข้องกับคอลเลกชัน ซึ่งช่วยสำรวจองค์ประกอบทั้งหมดของคอลเลกชันโดยไม่ต้องทำซ้ำ
คุณสามารถใช้รหัสต่อไปนี้เพื่อรับตัววนซ้ำสำหรับคอลเลกชันใดๆ:
Iterator<Type> it = name.iterator();
โดยที่nameชื่อของตัวแปรคอลเล็กชันTypeคือประเภทขององค์ประกอบของคอลเล็กชันiterator()เป็นหนึ่งในเมธอดของคอลเล็กชัน และitเป็นชื่อของตัวแปรวนซ้ำ
ตัววนซ้ำมี 3 วิธี:
| วิธี | คำอธิบาย |
|---|---|
|
ส่งกลับองค์ประกอบถัดไปในคอลเลกชัน |
|
ตรวจสอบว่ามีองค์ประกอบใดบ้างที่ยังไม่ได้สำรวจ |
|
ลบองค์ประกอบปัจจุบันของคอลเลกชัน |
เมธอดเหล่านี้ค่อนข้างคล้ายกับคลาสnextInt)และhasNextInt()วิธีการ ของ Scanner
เมธอดnext()ส่งคืนองค์ประกอบถัดไปของคอลเลกชันที่เราได้รับตัววนซ้ำ
เมธอดhasNext()ตรวจสอบว่าคอลเล็กชันมีองค์ประกอบเพิ่มเติมที่ตัววนซ้ำยังไม่ส่งคืนหรือไม่
นี่คือวิธีแสดงองค์ประกอบทั้งหมดของ a HashSet:
| รหัส | หมายเหตุ |
|---|---|
|
สร้างHashSetวัตถุที่เก็บStringองค์ประกอบ เราเพิ่มคำทักทายในภาษาต่างๆ ให้กับ setตัวแปร รับตัววนซ้ำวัตถุสำหรับ setชุด ตราบใดที่ยังมีองค์ประกอบ รับองค์ประกอบถัดไป แสดงองค์ประกอบบนหน้าจอ |
3. For-eachวนซ้ำ
ข้อเสียเปรียบหลักของตัววนซ้ำคือโค้ดของคุณจะยุ่งยากกว่าการใช้forลูป
ในการเปรียบเทียบ ลองแสดงรายการโดยใช้forการวนซ้ำและใช้ตัววนซ้ำ:
| วนซ้ำ | สำหรับลูป |
|---|---|
|
|
ใช่ มันจะดีกว่ามากที่จะสำรวจองค์ประกอบของArrayListการใช้ลูป — ทุกอย่างจะสั้นลง
แต่ผู้สร้างของ Java ตัดสินใจเทน้ำตาลใส่เราอีกครั้ง โชคดีสำหรับเรา มันเป็นน้ำตาลวากยสัมพันธ์
พวกเขาสร้างลูปชนิดใหม่ให้กับ Java และเรียกมันว่าfor-eachลูป นี่คือลักษณะโดยทั่วไป:
for(Type name:collection)
โดยที่collectionชื่อของตัวแปรคอลเล็กชันTypeคือประเภทขององค์ประกอบในคอลเล็กชัน และnameเป็นชื่อของตัวแปรที่รับค่าถัดไปจากคอลเล็กชันในการวนซ้ำแต่ละครั้ง
การวนซ้ำประเภทนี้จะวนซ้ำองค์ประกอบทั้งหมดของคอลเล็กชันโดยใช้ตัววนซ้ำโดยปริยาย นี่คือวิธีการทำงานจริง:
| สำหรับแต่ละวง | สิ่งที่คอมไพเลอร์เห็น: วนซ้ำด้วยตัววนซ้ำ |
|---|---|
|
|
เมื่อคอมไพเลอร์พบfor-eachการวนซ้ำในโค้ดของคุณ ก็จะแทนที่ด้วยโค้ดทางด้านขวา: จะเพิ่มการเรียกใช้เพื่อรับตัววนซ้ำพร้อมกับการเรียกเมธอดอื่นๆ ที่ขาดหายไป
โปรแกรมเมอร์ชอบfor-eachลูปและมักจะใช้มันเมื่อต้องการวนซ้ำองค์ประกอบทั้งหมดของคอลเลกชัน
แม้แต่การวนซ้ำArrayListรายการโดยใช้for-eachการวนซ้ำก็ยังดูสั้นกว่า:
| สำหรับแต่ละวง | สำหรับลูป |
|---|---|
|
|
4. การลบองค์ประกอบในfor-eachลูป
ลูfor-eachปมีข้อเสียอย่างหนึ่ง: ไม่สามารถลบองค์ประกอบได้อย่างถูกต้อง หากคุณเขียนโค้ดแบบนี้ คุณจะได้รับข้อผิดพลาด
| รหัส | บันทึก |
|---|---|
|
การดำเนินการลบจะทำให้เกิดข้อผิดพลาด! |
นี่เป็นรหัสที่ดีและเข้าใจได้ แต่มันใช้งานไม่ได้
คุณไม่สามารถเปลี่ยนคอลเลกชั่นได้ในขณะที่คุณกำลังสำรวจมันด้วยตัววนซ้ำ
มีสามวิธีในการหลีกเลี่ยงข้อจำกัดนี้
1. ใช้ลูปประเภทอื่น
When traversing an ArrayList collectionคุณสามารถใช้ลูปธรรมดากับตัวแปรiตัวนับได้
| รหัส |
|---|
|
อย่างไรก็ตามตัวเลือกนี้ไม่เหมาะสำหรับHashSetคอHashMapลเลกชัน
2. ใช้ตัววนซ้ำที่ชัดเจน
คุณสามารถใช้ iterator อย่างชัดเจนและเรียกremove()เมธอด ของมัน
| รุ่นที่ใช้งาน | เวอร์ชันที่ใช้งานไม่ได้ |
|---|---|
|
|
โปรดทราบว่าเราเรียกremove()เมธอดบน iterator object! ตัววนซ้ำทราบว่ารายการถูกลบแล้วและสามารถจัดการกับสถานการณ์ได้อย่างถูกต้อง
3. ใช้สำเนาของคอลเลกชัน
คุณยังสามารถสร้างสำเนาของคอลเลกชัน จากนั้นใช้สำเนาในลูfor-eachปและลบองค์ประกอบออกจากคอลเลกชันต้นฉบับ
| รหัส | บันทึก |
|---|---|
|
การสร้างสำเนาของคอลเลกชันนั้นง่ายมาก การวนซ้ำจะใช้ตัววนซ้ำสำหรับสำเนาของคอลเลกชัน องค์ประกอบจะถูกลบออกจาก listคอลเลกชัน |
คอลเลกชันถูกคัดลอกค่อนข้างเร็วเนื่องจากองค์ประกอบไม่ได้ซ้ำกัน คอลเลกชันใหม่จะเก็บการอ้างอิงถึงองค์ประกอบที่มีอยู่แล้วในคอลเลกชันเก่าแทน
GO TO FULL VERSION