簡體   English   中英

循環內的變量聲明

[英]Variable declaration inside a loop

我在整個編程過程中遇到的一個常見困境是在循環中聲明變量。 說我必須執行以下操作:

List list=myObject.getList();
Iterator itr=list.iterator();
while (itr.hasNext()){
    BusinessObject myBo=(BusinessObject)itr.next();
    process(myBo);
}

在上面的代碼片段中, myBo是應該在循環外聲明還是在循環中聲明它不會對內存和性能造成損害?

在循環內聲明它不會對內存和性能造成任何損害。

如果可能,請使用List<BusinessObject>Iterator<BusinessObject>來避免強制轉換:

List<BusinessObject> list = myObject.getList();
Iterator<BusinessObject> itr = list.iterator();

while (itr.hasNext()) {
   process(itr.next());
}

良好軟件設計的一個原則是限制局部變量的范圍,即在最后一次使用該變量后不久結束的塊內及時聲明它們。 這不會影響性能或其他“硬”方面,但會使程序更易讀,更易於分析。

總之,做你正在做的事情被認為是好的。

myBo只是對對象的引用(由itr.next()返回)。 因此,它所需的內存量非常小,並且只創建一次,並且在循環內添加它不應該影響您的程序。 IMO,在它所使用的循環中聲明它實際上有助於使其更具可讀性。

你的循環最優雅的解決方案是增強for循環(java 5或更新版本):

List<BusinessObject> list = myObject.getList();

for( BusinessObject myBo : list ) {
    process(myBo);
}

但即使您提供的代碼也沒有性能問題,因為所有臨時變量只保存對BusinessObject的引用,這非常便宜。

它不會造成任何內存傷害。

除非您省略某些代碼,否則您可以完全跳過聲明:

while (itr.hasNext()){
    //BusinessObject myBo=(BusinessObject)itr.next();
    process((BusinessObject)itr.next());
} 

只需用javap -c [ClassName]查看字節代碼即可。 這是一個演示一些帶循環的一次性變量示例的類。 相關的字節碼轉儲在注釋中:

class HelloWorldLoopsAnnotated {
    //
    // HelloWorldLoopsAnnotated();
    //   Code:
    //    0:   aload_0
    //    1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
    //    4:   return
    ////////////////////////////////////////////////////////////////////////////

    void stringDeclaredInsideLoop(){
        while (true) {
            // 0:   ldc #2; //String Hello World!
            String greeting = "Hello World!";
            doNothing(greeting);
        }
    }
    //
    // void stringDeclaredInsideLoop();
    //   Code:
    //    0:   ldc #2; //String Hello World!
    //    2:   astore_1
    //    3:   aload_0
    //    4:   aload_1
    //    5:   invokespecial   #3; //Method doNothing:(Ljava/lang/String;)V
    //    8:   goto    0
    ////////////////////////////////////////////////////////////////////////////

    void stringDeclaredOutsideLoop(){
        String greeting;
        while (true) {
            greeting = "Hello World!";
            doNothing(greeting);
        }
    }
    //
    // void stringDeclaredOutsideLoop();
    //   Code:
    //    0:   ldc #2; //String Hello World!
    //    2:   astore_1
    //    3:   aload_0
    //    4:   aload_1
    //    5:   invokespecial   #3; //Method doNothing:(Ljava/lang/String;)V
    //    8:   goto    0
    ////////////////////////////////////////////////////////////////////////////

    void stringAsDirectArgument(){
        while (true) {
            doNothing("Hello World!");
        }
    }
    // void stringAsDirectArgument();
    //   Code:
    //    0:   aload_0
    //    1:   ldc #2; //String Hello World!
    //    3:   invokespecial   #3; //Method doNothing:(Ljava/lang/String;)V
    //    6:   goto    0
    ////////////////////////////////////////////////////////////////////////////

    private void doNothing(String s) {
    }
}

stringDeclaredInsideLoop()stringDeclaredOutsideLoop()產生相同的六指令字節碼。 stringDeclaredInsideLoop()仍然獲勝: 有限的范圍是最好的

經過一番思考之后,我無法真正看到緊縮范圍會如何影響性能:堆棧中相同的數據需要相同的指令。

但是, stringAsDirectArgument()僅在四條指令中定義操作。 低內存環境(例如我笨拙的手機)可能會欣賞優化,同時閱讀代碼的同事可能不會,因此在從代碼中刪除字節之前要做出判斷。

請參閱完整要點了解更多信息。

如果短 - 沒有。 在C ++中,如果myBo是通過復制創建的,那么可能是一個問題,但在Java中總是使用引用,不是嗎?
為了性能,它更好地優化您在進程中所做的事情()

臨時引用myBo放在堆棧上,應該主要進行優化。 您的代碼不應該有任何性能損失。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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