[英]How is Java's for loop code generated by the compiler
Java 的 for 循環代碼是如何由編譯器生成的?
例如,如果我有:
for(String s : getStringArray() )
{
//do something with s
}
其中getStringArray()
是一個返回我想要循環的數組的函數,函數是總是被調用還是只被調用一次? 一般來說,使用此構造的循環代碼的最佳程度如何?
for
循環的語義以下是Java Language Specification 3rd Edition的相關摘錄,為了清晰起見,略作編輯:
JLS 14.14.2 增強的
for
語句增強的
for
語句具有以下形式:for ( Type Identifier : Expression ) Statement
如果
Expression
的類型是數組類型T[]
,那么增強的for
語句的含義由以下基本for
語句給出:T[] a = Expression; for (int i = 0; i < a.length; i++) { Type Identifier = a[i]; Statement }
其中
a
和i
是編譯器生成的標識符,它們不同於任何其他標識符(編譯器生成的或以其他方式生成的),這些標識符在增強的for
語句發生時的范圍內。
所以實際上該語言確實保證Expression
只會被評估一次。
為了完整Iterable
當Expression
是Iterable
類型時,這里是等價的:
JLS 14.14.2 增強的
for
語句增強的
for
語句具有以下形式:for ( Type Identifier : Expression ) Statement
如果
Expression
的類型是Iterable
的子Iterable
,那么讓I
成為表達式Expression.iterator()
的類型。 增強的for
語句等效於以下形式的基本for
語句:for (I iter = Expression.iterator(); iter.hasNext(); ) { Type Identifier = iter.next(); Statement }
其中
iter
是編譯器生成的標識符,它不同於在增強的for
語句發生的點范圍內的任何其他標識符(編譯器生成的或其他方式)。
請注意,如果Expression
既不是Iterable
也不是數組,則會出現編譯時錯誤,因此上述兩種情況是您可以使用增強的for
循環的唯一情況。 此外,為了清楚起見,上面的引用省略了有關for
循環上附加的任何標簽和Identifier
上附加的任何修飾符的信息,但這些都按預期處理。
for
循環的性能這是Effective Java 2nd Edition, Item 46的引用:Prefer for-each 循環而不是傳統的 for 循環
1.5 版中引入的 for-each 循環通過完全隱藏迭代器或索引變量來消除混亂和出錯的機會。 由此產生的習語同樣適用於集合和數組。 請注意,使用 for-each 循環沒有性能損失,即使對於數組也是如此。 事實上,在某些情況下,它可能比普通的
for
循環提供輕微的性能優勢,因為它只計算一次數組索引的限制。 雖然您可以手動完成此操作,但程序員並不總是這樣做。
因此,這本書聲稱實際上一些編譯器超越了 JLS 翻譯,並對 for-each 循環執行了額外的優化(當然,同時仍然保持其語義)。
總之,您不必擔心 for-each 循環的性能。 語言的規范是合理的( Expression
只計算一次),正是因為這是許多場景中的首選構造,編譯器將確保盡其所能優化它們。
JDK 1.4 引入了RandomAccess
接口。 它旨在為算法提供提示,對於給定的List
實現,迭代更有效:
for (int i = 0, n = list.size(); i < n; i++) {
list.get(i);
}
比
for (Iterator i = list.iterator(); i.hasNext(); ) {
i.next();
}
foreach 循環是否考慮到了這一點? 或者它是否完全忽略了一個事實,即給定的 Iterable 實際上是一個 List?
應該注意的是,這意味着添加一個(iterable instanceof List && iterable instanceof RandomAccess)
測試和向下轉換到List
會起作用,這會增加一個並不總是值得的開銷,並且可以被認為是編譯器語法的過早優化糖功能。
編譯器可能只調用一次,但您可以依賴它。 這可能不是一個好的編碼習慣。 如果getStringArray()
每次都返回相同的數組,為什么不先設置一個變量呢?
編輯- 答案隨收到的評論而改變。
for 循環與 javascript 中的循環相同,因此無需擔心
例子:
for(int i=0;i<10;i++)
{
System.out.Println(i);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.