1. 程式人生 > >Java 的三種迴圈:foreach,Iterator 和 classic for loop

Java 的三種迴圈:foreach,Iterator 和 classic for loop

不得不說,java語言在提供了這三種迴圈方式帶來靈活性的同時,同時也將一些“混亂”引入了進來。

這裡的“混亂”並不是真正意義上的混亂,而是由於沒有統一的風格而帶來使用習慣的問題——想象一下,如果同一個專案中這三種都有人用,閱讀起來真是五味雜陳啊。

有人要問了,那麼,這三種到底哪種好呢?

在回答這個問題之前,能告訴我“好”的定義是什麼嗎?

我所認為的好,無非2點——1、程式碼簡潔;2、效能高效

接下來,我們對這3種for迴圈方式一一評估。

Classic for loop

首先,來看看classic for loop.

<pre name="code" class="java">List<String> birds = new ArrayList<String>() {
	{
		add("magpie");
		add("crow");
		add("emu");
	}
};
for (int i = 0; i < birds.size(); i++) {
	String bird = birds.get(i);
}

這種方式,程式碼風格還好,可惜的是,有個隱藏的效能問題。

對於List介面的眾多實現類來講,並不是每個實現的get(i)都是O(1)時間的。比如LinkedList的時間複雜度就是O(n)。

這樣,每次呼叫get方法的效能從固定時間變為了隨著n增長而增長的線性時間。

(這裡,我不打算討論list.size()方法的效能,如果僅僅從LinkedList和ArrayList這樣常用的方法來看,它的效能損失可以忽略不計,除非是追求極致)

(圖片引用自:ArrayList vs. LinkedList vs. Vector [1])

換句話講,如果上面的List實現換成LinkedList,這樣的程式碼就可能存在隱藏的效能問題。(當List比較大且頻繁呼叫的情況下)

而恰恰Java又是提倡隱藏實現細節的語言,使用者往往並不知道傳入的List實現究竟是哪一種。所以……可能,僅僅是可能,一個隱藏的效能地雷埋下了。

Iterator 

現在,來看看 iterator for 迴圈。

上面那個例子,稍加改動就成為了下面這樣:

List<String> birds = new ArrayList<String>() {
	{
		add("magpie");
		add("crow");
		add("emu");
	}
};
for (Iterator<String> itr = birds.iterator(); itr.hasNext();) {
	String bird = itr.next();
}

從效能角度來看,這種方式還好,獲取每個元素都是固定時間,但是,從程式碼風格來看,略顯複雜了。

不過,iterator有個優點,就是可以在迴圈體內刪除列表中的元素可能成功-依賴List的具體實現),而其他的2種方式不行。

List<String> birds = new ArrayList<String>() {
	{
		add("magpie");
		add("crow");
		add("emu");
	}
};
// 下面的for迴圈執行後,birds列表將被清空
for (Iterator<String> itr = birds.iterator(); itr.hasNext();) {
	String bird = itr.next();
	itr.remove();
}

而下面這種方式是錯誤的
List<String> birds = new ArrayList<String>() {
	{
		add("magpie");
		add("crow");
		add("emu");
	}
};
// 下面的for迴圈執行時將會丟擲異常
for (String bird : birds) {
	birds.remove(bird);
}

Foreach

最後,來看看用JDK5引入的神器,foreach迴圈。

List<String> birds = new ArrayList<String>() {
	{
		add("magpie");
		add("crow");
		add("emu");
	}
};
for (String bird : birds) {
}
從程式碼風格上來看,它最簡潔。那麼效能如何呢?

其實,對於集合來說,它只是Iterator迴圈的包裝(甜頭),編寫程式碼的時候簡化了程式碼,而編譯的時候依然是用Iterator實現的。

對於陣列型別,還是用的classic for loop實現。

所以,效能也是最優的。

對比一下這三種方式,我們可以得出結論:

簡潔性 效能
classic for loop OK 可能會差
Iterator
foreach

所以,如果可以,儘量選擇使用foreach迴圈,簡潔且高效。

引用: