foreach
ใช้ iterators ใต้ฝากระโปรงต่อไป จริงๆแล้วมันเป็นแค่น้ำตาลซินแทคติค
พิจารณาโปรแกรมต่อไปนี้:
import java.util.List;
import java.util.ArrayList;
public class Whatever {
private final List<Integer> list = new ArrayList<>();
public void main() {
for(Integer i : list) {
}
}
}
ลองมารวบรวมไว้ด้วยjavac Whatever.java
,
และอ่าน bytecode ถอดชิ้นส่วนของmain()
การใช้javap -c Whatever
:
public void main();
Code:
0: aload_0
1: getfield #4 // Field list:Ljava/util/List;
4: invokeinterface #5, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
9: astore_1
10: aload_1
11: invokeinterface #6, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
16: ifeq 32
19: aload_1
20: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
25: checkcast #8 // class java/lang/Integer
28: astore_2
29: goto 10
32: return
เราจะเห็นว่าforeach
คอมไพล์ลงในโปรแกรมซึ่ง:
- สร้างตัววนซ้ำโดยใช้
List.iterator()
- หาก
Iterator.hasNext()
: เรียกใช้Iterator.next()
และวนรอบต่อไป
ในฐานะที่เป็น "ทำไมไม่ห่วงไร้ประโยชน์นี้ได้รับการปรับให้เหมาะสมออกจากรหัสเรียบเรียงเราจะเห็นว่ามันไม่ได้ทำอะไรกับรายการรายการ": ดีก็เป็นไปได้สำหรับคุณที่จะรหัส iterable ดังกล่าวของคุณที่.iterator()
มีผลข้างเคียง หรือดังนั้นจึง.hasNext()
มีผลข้างเคียงหรือผลที่ตามมาอย่างมีความหมาย
คุณสามารถจินตนาการได้อย่างง่ายดายว่าการทำซ้ำที่เป็นตัวแทนของคิวรีแบบเลื่อนได้จากฐานข้อมูลอาจทำอะไรบางอย่างที่น่าทึ่ง.hasNext()
(เช่นการติดต่อฐานข้อมูลหรือปิดเคอร์เซอร์เพราะคุณถึงจุดสิ้นสุดของชุดผลลัพธ์)
ดังนั้นแม้ว่าเราจะสามารถพิสูจน์ได้ว่าไม่มีอะไรเกิดขึ้นในร่างกายของลูป ... มันมีราคาแพงกว่า (ยากที่จะเข้าใจได้) เพื่อพิสูจน์ว่าไม่มีอะไรที่มีความหมาย / เป็นผลสืบเนื่องเกิดขึ้นเมื่อเราย้ำ คอมไพเลอร์จะต้องปล่อยให้ร่างกายวนที่ว่างเปล่านี้ในโปรแกรม
ดีที่สุดที่เราจะหวังจะเป็นคอมไพเลอร์เตือน เป็นเรื่องที่น่าสนใจที่javac -Xlint:all Whatever.java
ไม่ได้เตือนเราเกี่ยวกับเนื้อความที่ว่างเปล่านี้ IntelliJ IDEA ทำเช่นนั้น เป็นที่ยอมรับว่าฉันได้กำหนดค่า IntelliJ ให้ใช้ Eclipse Compiler แต่นั่นอาจไม่ใช่สาเหตุ