2010-01-05 13 views
8

एक सामान्य दुविधा जो मैंने पूरे प्रोग्रामिंग का सामना किया है वह एक लूप के अंदर चर घोषित करने के बारे में है। myBo पाश बाहर घोषित किया जाना चाहिएलूप के अंदर परिवर्तनीय घोषणा

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

ऊपर स्निपेट में, या करता है पाश अंदर यह घोषित स्मृति और प्रदर्शन करने के लिए नुकसान का कारण नहीं: मैं निम्नलिखित की तरह कुछ प्रदर्शन करने के लिए है कहो?

उत्तर

4

myBo बस किसी ऑब्जेक्ट का संदर्भ है (जिसे itr.next() द्वारा वापस किया जाता है)। चूंकि इसकी आवश्यक स्मृति की मात्रा बहुत छोटी है, और केवल एक बार बनाई गई है, और इसे लूप के अंदर जोड़ना आपके प्रोग्राम को प्रभावित नहीं करना चाहिए। आईएमओ, इसे लूप के अंदर घोषित करता है जहां इसका उपयोग किया जाता है वास्तव में इसे और अधिक पठनीय बनाने में मदद करता है।

+0

यह उत्तर भ्रामक है, क्योंकि इसका तात्पर्य है कि प्रत्येक पुनरावृत्ति के बाद संदर्भ-चर आवंटित किया जाता है, जो * सत्य नहीं है। –

+0

@ ब्लूराजा - डैनी Pflughoeft: जैसा कि मैंने अपने जवाब में कहा था, यह केवल एक वस्तु के लिए * संदर्भ * बना रहा है, पूरे ऑब्जेक्ट को आवंटित नहीं कर रहा है। यही कारण है कि स्मृति की मात्रा बहुत छोटी है - क्योंकि केवल संदर्भ के लिए आवश्यक कुछ बाइट्स शामिल हैं। – MAK

+0

हाँ मैं समझता हूं; लेकिन यहां तक ​​कि उस संदर्भ (पॉइंटर स्वयं) को केवल एक बार आवंटित किया जाता है, जो वाक्यांश * * आवंटित/इसे हटाने से आपके कार्यक्रम को महत्वपूर्ण रूप से प्रभावित नहीं करना चाहिए "* का अर्थ है। –

8

लूप के अंदर इसे घोषित करने से स्मृति और प्रदर्शन को कोई नुकसान नहीं पहुंचाएगा। संभावित उपयोग List<BusinessObject> और Iterator<BusinessObject> कास्टिंग से बचने के लिए

5

हैं:

अच्छा सॉफ्टवेयर डिजाइन की
List<BusinessObject> list = myObject.getList(); 
Iterator<BusinessObject> itr = list.iterator(); 

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

बेशक केवल 1.5 और उच्चतर में काम करता है। हर कोई इतना भाग्यशाली नहीं है :) – extraneon

5

एक सिद्धांत है स्थानीय चर का दायरा सीमित करने के लिए, यानी उन्हें सिर्फ एक ब्लॉक है कि जल्द ही बाद ही समाप्त होता भीतर समय में घोषित करने के लिए उस चर का अंतिम उपयोग। यह प्रदर्शन या अन्य "कठिन" पहलुओं को प्रभावित नहीं करता है लेकिन प्रोग्राम को अधिक पढ़ने योग्य और विश्लेषण करने में आसान बनाता है।

संक्षेप में, जो भी आप कर रहे हैं वह अच्छा माना जाता है।

1

यदि छोटा - नहीं। सी ++ में यह समस्या हो सकती है यदि MyBo की प्रतिलिपि बनाकर बनाया गया है लेकिन जावा में हमेशा संदर्भों का उपयोग किया जाता है, है ना?
प्रदर्शन के लिए, अपने बेहतर कुछ आप इस प्रक्रिया में क्या कर रहे हैं अनुकूलन करने के लिए()

0

अस्थायी संदर्भ myBo ढेर पर डाल दिया जाता है और ज्यादातर दूर अनुकूलित किया जाना चाहिए। आपके कोड में कोई प्रदर्शन जुर्माना नहीं होना चाहिए।

4

अपने पाश के लिए सबसे सुरुचिपूर्ण समाधान एक पाश (जावा 5 या नया) के लिए बढ़ाया जाएगा:

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

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

लेकिन फिर भी कोड आप कोई प्रदर्शन समस्या नहीं होगी प्रदान की है, साथ क्योंकि सभी अस्थायी चर केवल BusinessObject पर संदर्भ रखें, जो कि बहुत सस्ता है।

2

इससे कोई स्मृति हानि नहीं होती है।

BTW जब तक आप कुछ कोड को छोड़ते हुए कर रहे हैं आप पूरी तरह घोषणा को छोड़ सकते हैं:

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

बस 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(), हालांकि, केवल चार निर्देशों में ऑपरेशन को परिभाषित करता है। कम मेमोरी वातावरण (जैसे मेरा शानदार बेवकूफ फोन) ऑप्टिमाइज़ेशन की सराहना कर सकता है जबकि आपके कोड को पढ़ने वाले सहयोगी नहीं हो सकते हैं, इसलिए अपने कोड से शेविंग बाइट्स से पहले निर्णय लें।

अधिक के लिए full gist देखें।

संबंधित मुद्दे