簡體   English   中英

Java的for循環代碼是如何由編譯器生成的

[英]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 }

其中ai是編譯器生成的標識符,它們不同於任何其他標識符(編譯器生成的或以其他方式生成的),這些標識符在增強的for語句發生時的范圍內。

所以實際上該語言確實保證Expression只會被評估一次。

為了完整IterableExpressionIterable類型時,這里是等價的:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM