記得大學上C語言的課,第一次遇到的問題就是迴圈結構裡面的 for
。
選擇結構的 if
非常易懂,和日常生活的判斷沒有區別。
迴圈結構的 while
同樣比較好理解。
本質上是一個判斷
而 for
會稍微複雜一些。
for (init-expr; test-expr; update-expr)
body-statement
在實際的語意等同於(唯一區別是init-expr一個是內部變數,一個是外部變數)
init-expr
while (test-expr) {
body-statement
update-expr
}
那麼我們為什麼要設計一個不那麼好理解的迴圈結構呢?
因為這時候才入了程式設計的門————抽象,以及約定。
如果我們再往底層挖,會發現在組合語言中是不存在while
、for
關鍵字的。
最開始的程式總是從左到右,從上到下一條路走到黑的。
後面程式設計人員意識到編寫重複的程式碼過於麻煩才創造了 loop
。
所以最開始需要人工寫一個for或者while迴圈。
while
好理解在於和自然語言(英語)完全符合。
當 條件滿足 時, {
執行 流程;
}
而 for
迴圈的好處在於規範了 while
的使用。
// 傳統while迴圈
int i = 0;
while (i < 10) {
handleX();
i++;
int j = 0;
while (j < 5) {
handleY();
j++;
}
}
// for迴圈
for (int i = 0; i < 10; i++) {
handleX();
for (int j = 0; j < 5; j++) {
handleY();
}
}
所以 for 迴圈的出現也意味著程式設計人員開始在意的不僅僅是功能,而且看重可讀性。
然而這並不會被滿足。
之後還出現了
for
,部分語言的for-each,for...in
。lamdba
表示式中的 forEach()
方法。注意:以下按 Java 實現的 foreach 舉例。(其他程式語言不太熟悉)
for
foreach
的規則
foreach
的集合都必須實現 Iterable
介面iterator()
獲取 iterator
物件iterator.hasNext()
判斷是否存在元素。iterator.next()
獲取下一個元素。iterator.remove()
移除返回的元素。(可選)for
的語法 List<String> list = Arrays.asList("1", "2", "3", "4", "5");
// for 版本
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// foreach 版本
for (String e : list) {
System.out.println(e);
}
// 去"糖"後的while版本
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
可以看出,foreach
對於 for、while
來說,好處是更加簡單,符合直覺。
hasNext()
處理。next()
處理。hasNext(), next()
邏輯,程式碼更易讀。forEach()
Java 7/8 受到了函數式語言的影響,實現了更簡練的寫法。
// Iterable<T> 內實現的forEach
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
List<String> list = Arrays.asList("1", "2", "3", "4", "5");
// forEach()
list.forEach(i -> System.out.print(i));
// 方法參照
list.forEach(System.out::print);
可以看出,forEach()的好處顯而易見。
foreach
更少,只關注遍歷元素,甚至連元素型別都可以省略。可以看出,程式設計人員一直追尋的是更簡單,更易讀的程式碼。