ใน Java for-each loop ช่วยลดความซับซ้อนของกระบวนการ traversal ของคอลเลกชั่นหรืออาเรย์ใดๆ แต่ไม่ใช่ว่าโปรแกรมเมอร์ Java ทุกคนจะรู้รายละเอียดบางอย่างของ for-each loop ที่จะอธิบายในบทความนี้ ไม่เหมือนกับคำศัพท์อื่นๆ ที่เผยแพร่ใน Java 5: alias-released generics, auto-encapsulation และ variadic parameter นักพัฒนา Java ใช้ for-each loops บ่อยกว่าคุณสมบัติอื่นๆ แต่เมื่อถามว่า Advanced for-each loops ทำงานอย่างไร หรืออะไรคือพื้นฐาน ข้อกำหนดเมื่อใช้ Collection ในแต่ละ loop ไม่ใช่ทุกคนที่จะตอบได้
บทช่วยสอนและตัวอย่างนี้มีจุดมุ่งหมายเพื่อเติมเต็มช่องว่างนั้นด้วยการเจาะลึกปริศนาที่น่าสนใจสองสามข้อในแต่ละลูป โอเค ไม่ต้องลงรายละเอียด มาดูปัญหาแรกของเรากับ Java5 สำหรับแต่ละลูปกันดีกว่า
คำถามวงวนขั้นสูง 1
พิจารณารหัสต่อไปนี้ที่สำรวจผ่านตัวรวบรวมหรือคลาสคอลเลกชันที่ผู้ใช้กำหนด รหัสนี้จะพิมพ์อะไร ไม่ว่าจะส่งข้อยกเว้นหรือข้อผิดพลาดของคอมไพเลอร์:
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบบรรจุภัณฑ์
-
* Java Class เพื่อแสดงวิธีการทำงานของ for-each loop ใน Java
-
คลาสสาธารณะ ForEachTest {
โมฆะคงที่สาธารณะ main (String args []) {
CustomCollection<String> myCollection = CustomCollection ใหม่<String>();
myCollection.add("จาวา");
myCollection.add("สกาล่า");
myCollection.add("แรง");
//โค้ดนี้ใช้ทำอะไร, พิมพ์ภาษา, ยกเว้นข้อผิดพลาดหรือข้อผิดพลาดในการคอมไพล์
สำหรับ (ภาษาสตริง: myCollection){
System.out.println (ภาษา);
-
-
-
ด้านล่างนี้คือคลาส CustomCollection ของเรา ซึ่งเป็นคลาสทั่วไปที่เหมือนกับคลาส Collection อื่นๆ ที่ต้องอาศัย ArrayList และมีวิธีการในการเพิ่มและลบรายการออกจากคอลเลกชัน
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบบรรจุภัณฑ์
CustomCollection คลาสสาธารณะ <T>{
ที่เก็บข้อมูล ArrayList <T> ส่วนตัว;
CustomCollection สาธารณะ () {
ที่ฝากข้อมูล = ArrayList ใหม่ ();
-
ขนาด int สาธารณะ () {
กลับ bucket.size();
-
บูลีนสาธารณะ isEmpty() {
กลับถัง isEmpty ();
-
บูลีนสาธารณะมี (T o) {
กลับ bucket.contains (o);
-
เพิ่มบูลีนสาธารณะ (T e) {
กลับ bucket.add (e);
-
ลบบูลีนสาธารณะ (T o) {
กลับ bucket.remove (o);
-
-
คำตอบ:
โค้ดข้างต้นจะไม่คอมไพล์เนื่องจากคลาส CustomCollection ของเราไม่ได้ใช้อินเทอร์เฟซ java.lang.Iterable ข้อผิดพลาดในการคอมไพล์เวลามีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
ข้อยกเว้นในเธรด "main" java.lang.RuntimeException: ซอร์สโค้ดที่ไม่สามารถคอมไพล์ได้ - for-each ไม่สามารถใช้ได้กับประเภทนิพจน์
จำเป็น: อาร์เรย์หรือ java.lang.Iterable
พบ: test.CustomCollection
ที่ test.ForEachTest.main (ForEachTest.java:24)
ข้อเท็จจริงที่น่าสนใจในการเรียนรู้จากสิ่งนี้ก็คือ for-each loop ใช้กับอาร์เรย์ Java และคลาส Collection ที่ใช้อินเทอร์เฟซ Iterable เท่านั้น และเนื่องจากคลาส Collection ในตัวทั้งหมดใช้อินเทอร์เฟซ java.util.Collection และได้รับสืบทอด Iterable สิ่งนี้ รายละเอียดที่มักถูกมองข้ามสามารถดูได้ในการประกาศประเภทของอินเทอร์เฟซคอลเลกชัน "คอลเลกชันอินเทอร์เฟซสาธารณะขยาย Iterable" ดังนั้น เพื่อแก้ไขปัญหาข้างต้น คุณสามารถเลือกให้ CustomCollection ใช้อินเทอร์เฟซ Collection หรือสืบทอด AbstractCollection ซึ่งเป็นการใช้งานสากลเริ่มต้น และแสดงวิธีใช้คลาสนามธรรมและอินเทอร์เฟซพร้อมกันเพื่อความยืดหยุ่นที่ดีขึ้น ตอนนี้เรามาดูปริศนาที่สองของ for-each loop:
ปัญหาที่สองของ Java สำหรับแต่ละลูป:
ตัวอย่างโค้ดต่อไปนี้จะเกิด ConcurrentModificationException ที่นี่เราใช้ตัววนซ้ำมาตรฐานและ for-each loop เพื่อวนซ้ำผ่าน ArrayList แล้วลบองค์ประกอบ คุณต้องค้นหาว่าโค้ดชิ้นใดที่จะส่ง ConcurrentModificationException และเพราะเหตุใด โปรดทราบว่าคำตอบอาจเป็นได้ทั้งสองอย่าง หรืออย่างใดอย่างหนึ่งก็ได้
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบบรรจุภัณฑ์
นำเข้า java.util.ArrayList;
นำเข้า java.util.Collection;
นำเข้า java.util.Iterator;
-
* คลาส Java เพื่อแสดงการทำงานภายในของแต่ละลูปใน Java
* @ผู้เขียน Javin Paul
-
คลาสสาธารณะ ForEachTest2 {
โมฆะคงที่สาธารณะ main (String args []) {
คอลเลกชัน<String> list = new ArrayList<String>();
list.add("Android");
list.add("ไอโฟน");
list.add("วินโดวส์โมบาย");
// รหัสใดที่จะโยน ConcurrentModificationException ทั้งสองอย่าง
// ไม่มีหรืออย่างใดอย่างหนึ่ง
// ตัวอย่างที่ 1
ตัววนซ้ำ<สตริง> itr = list.iterator();
ในขณะที่(itr.hasNext()){
สตริง lang = itr.next();
list.remove(lang);
-
// ตัวอย่างที่ 2
สำหรับ (ภาษาสตริง: รายการ) {
list.remove (ภาษา);
-
-
-
นักพัฒนา Java ประมาณ 70% จะบอกว่าบล็อกโค้ดแรกจะส่งข้อยกเว้น ConcurrentModificationException เนื่องจากเราไม่ได้ใช้วิธีการลบของตัววนซ้ำเพื่อลบองค์ประกอบ แต่ใช้วิธีการลบ () ของ ArrayList อย่างไรก็ตาม มีนักพัฒนา Java จำนวนไม่มากที่บอกว่าปัญหาเดียวกันนี้เกิดขึ้นกับ for-each loop เนื่องจากเราไม่ได้ใช้ตัววนซ้ำที่นี่ ในความเป็นจริง ข้อมูลโค้ดที่สองยังส่ง ConcurrentModificationException ซึ่งจะเห็นได้ชัดหลังจากแก้ไขความสับสนครั้งแรก เนื่องจาก for-each loop ใช้ Iterator ภายในเพื่อสำรวจคอลเลกชัน จึงเรียก Iterator.next() ซึ่งจะตรวจสอบการเปลี่ยนแปลง (ขององค์ประกอบ) และส่ง ConcurrentModificationException คุณสามารถดูสิ่งนี้ได้จากผลลัพธ์ด้านล่าง ซึ่งคุณจะได้รับเมื่อคุณเรียกใช้ตัวอย่างที่สองหลังจากแสดงความคิดเห็นในตัวอย่างแรก
คัดลอกรหัสรหัสดังต่อไปนี้:
ข้อยกเว้นในเธรด "main" java.util.ConcurrentModificationException
ที่ java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
ที่ java.util.AbstractList$Itr.next(AbstractList.java:343)
ที่ test.ForEachTest2.main (ForEachTest2.java:34)
นั่นคือทั้งหมดที่เกี่ยวกับ Java5 สำหรับแต่ละลูป เราพบปัญหามากมายที่โปรแกรมเมอร์ Java พบเมื่อเขียนโค้ดเพื่อวนซ้ำคลาส Collection โดยเฉพาะอย่างยิ่งเมื่อวนซ้ำคอลเลกชันในขณะที่ลบองค์ประกอบในเวลาเดียวกัน อย่าลืมใช้วิธีการลบของ Iterator เสมอเมื่อลบวัตถุออกจากคอลเลกชันใดๆ (เช่น แผนที่ เซ็ต หรือรายการ) นอกจากนี้ โปรดจำไว้ว่า for-each loop เป็นเพียงวากยสัมพันธ์ (น้ำตาลวากยสัมพันธ์) ที่อยู่เหนือการใช้งานมาตรฐานของ รหัส Iterator มาตรฐานน้ำตาล) เท่านั้น
หมายเหตุผู้แปล: น้ำตาลวากยสัมพันธ์ หรือแปลว่าไวยากรณ์เคลือบน้ำตาล เป็นคำที่คิดค้นโดยนักวิทยาศาสตร์คอมพิวเตอร์ชาวอังกฤษ ปีเตอร์ เจ. แลนดิน ซึ่งหมายถึงไวยากรณ์บางประเภทที่เพิ่มเข้าไปในภาษาคอมพิวเตอร์ ไวยากรณ์ไม่มีผลกระทบต่อการทำงานของภาษา ภาษาแต่ทำให้โปรแกรมเมอร์ใช้งานได้ง่ายขึ้น โดยทั่วไปแล้ว การใช้ไวยากรณ์น้ำตาลสามารถเพิ่มความสามารถในการอ่านของโปรแกรมได้ จึงช่วยลดโอกาสที่จะเกิดข้อผิดพลาดของโค้ดโปรแกรมได้