एक लूप के अंदर या बाहर चर घोषित करना


236

निम्नलिखित कार्य ठीक क्यों है?

String str;
while (condition) {
    str = calculateStr();
    .....
}

लेकिन यह एक खतरनाक / गलत कहा जाता है:

while (condition) {
    String str = calculateStr();
    .....
}

क्या लूप के बाहर चर घोषित करना आवश्यक है?

जवाबों:


289

स्थानीय चरों का दायरा हमेशा सबसे छोटा होना चाहिए।

आपके उदाहरण में, मुझे लगता strहै कि लूप के बाहर उपयोग नहीं किया जाता है while, अन्यथा आप सवाल नहीं पूछेंगे, क्योंकि इसे whileलूप के अंदर घोषित करना एक विकल्प नहीं होगा, क्योंकि यह संकलन नहीं करेगा।

तो, के बाद से strकिया गया है नहीं पाश बाहर किया, के लिए छोटी संभव गुंजाइश strहै भीतर , जबकि पाश।

तो, इसका उत्तर सशक्त रूप से है कि strपूरी तरह से लूप के भीतर घोषित किया जाना चाहिए। अगर नहीं, नहीं, और नहीं, लेकिन नहीं।

एकमात्र मामला जहां इस नियम का उल्लंघन किया जा सकता है, अगर किसी कारण से यह महत्वपूर्ण है कि हर घड़ी चक्र को कोड से बाहर निचोड़ना होगा, तो उस स्थिति में आप किसी बाहरी दायरे में किसी चीज को तत्काल करना और उसके बजाय उसका पुन: उपयोग करने पर विचार करना चाह सकते हैं। एक आंतरिक दायरे के हर पुनरावृत्ति पर इसे फिर से तत्काल करना। हालांकि, यह आपके उदाहरण पर लागू नहीं होता है, जावा में स्ट्रिंग्स की अपरिवर्तनीयता के कारण: स्ट्रै का एक नया उदाहरण हमेशा आपके लूप की शुरुआत में बनाया जाएगा और इसे इसके अंत में फेंक दिया जाएगा, इसलिए वहां वहाँ अनुकूलन करने के लिए कोई संभावना नहीं है।

संपादित करें: (उत्तर में मेरी टिप्पणी नीचे दर्ज कर रहा है)

किसी भी मामले में, चीजों को करने का सही तरीका यह है कि आप अपने सभी कोड को ठीक से लिखें, अपने उत्पाद के लिए एक प्रदर्शन की आवश्यकता स्थापित करें, इस आवश्यकता के खिलाफ अपने अंतिम उत्पाद को मापें, और यदि यह इसे संतुष्ट नहीं करता है, तो चीजों को अनुकूलित करें। और आमतौर पर जो कुछ भी होता है वह यह है कि आप कुछ अच्छे और औपचारिक एल्गोरिथम अनुकूलन के लिए कुछ ऐसे स्थानों को उपलब्ध करवाते हैं, जो हमारे कार्यक्रम को आपके संपूर्ण कोड बेस पर जाने और बदले में चीजों को हैक करने के बजाय हमारे प्रदर्शन की आवश्यकताओं को पूरा करते हैं। यहाँ और वहाँ घड़ी चक्र को निचोड़ने का आदेश।


2
अंतिम पैराग्राफ पर प्रश्न: यदि यह दूसरा था तो स्ट्रिंग जो अपरिवर्तनीय नहीं है तो क्या यह प्रभावित करता है?
हैरी जॉय

1
@HarryJoy हां, उदाहरण के लिए, StringBuilder को लें, जो कि परिवर्तनशील है। यदि आप लूप के प्रत्येक पुनरावृत्ति में एक नया स्ट्रिंग बनाने के लिए स्ट्रिंग स्ट्रिंग का उपयोग करते हैं, तो आप स्ट्रिंग के बाहर स्ट्रिंग स्ट्रिंग को आवंटित करके चीजों को अनुकूलित कर सकते हैं। लेकिन फिर भी, यह एक उचित अभ्यास नहीं है। यदि आप इसे बहुत अच्छे कारण के बिना करते हैं, तो यह समयपूर्व अनुकूलन है।
माइक नाइस

7
@HarryJoy चीजों को करने का सही तरीका है कि आप अपने सभी कोड को ठीक से लिखें , अपने उत्पाद के लिए एक प्रदर्शन की आवश्यकता स्थापित करें, इस आवश्यकता के खिलाफ अपने अंतिम उत्पाद को मापें, और यदि यह संतुष्ट नहीं करता है, तो चीजों को अनुकूलित करें। और क्या आपको पता है? आप आमतौर पर सिर्फ कुछ स्थानों में कुछ अच्छी और औपचारिक एल्गोरिदमिक अनुकूलन प्रदान करने में सक्षम होंगे जो आपके पूरे कोड बेस पर जाने के बजाय चाल करेंगे और यहां और वहां घड़ी चक्र को निचोड़ने के लिए चीजों को ट्विक और हैक करेंगे।
माइक नाकिस

2
@ मायनिकनेस मैं आप बहुत संकीर्ण दायरे में सोच रहे हैं।
बैठें

5
आप देखते हैं, आधुनिक मल्टी-गीगाहर्ट्ज़, मल्टी-कोर, पाइपलाइन, मल्टी-लेवल-मेमोरी-कैश सीपीयू हमें घड़ी चक्र के बारे में चिंता किए बिना सर्वोत्तम प्रथाओं का पालन करने की अनुमति देते हैं। इसके अलावा, अनुकूलन केवल सलाह दी जाती है यदि और केवल अगर यह निर्धारित किया गया है कि यह आवश्यक है, और जब यह आवश्यक है, तो अत्यधिक स्थानीयकृत दोहों में से एक आम तौर पर वांछित प्रदर्शन प्राप्त करेगा, इसलिए हमारे सभी कोड को पूरा करने की आवश्यकता नहीं है। प्रदर्शन के नाम पर कम हैक के साथ।
माइक नाकिस

293

मैंने उन दो (समान) उदाहरणों के बाइट कोड की तुलना की:

आइए 1. उदाहरण देखें :

package inside;

public class Test {
    public static void main(String[] args) {
        while(true){
            String str = String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

के बाद javac Test.java, javap -c Testआप प्राप्त करेंगे:

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

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

आइए २ उदाहरण देखें :

package outside;

public class Test {
    public static void main(String[] args) {
        String str;
        while(true){
            str =  String.valueOf(System.currentTimeMillis());
            System.out.println(str);
        }
    }
}

के बाद javac Test.java, javap -c Testआप प्राप्त करेंगे:

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

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method java/lang/System.currentTimeMillis:()J
   3:   invokestatic    #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
   6:   astore_1
   7:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  aload_1
   11:  invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    0

}

टिप्पणियों से पता चलता है कि उन दो उदाहरणों में कोई अंतर नहीं है । यह JVM विनिर्देशों का परिणाम है ...

लेकिन सर्वश्रेष्ठ कोडिंग अभ्यास के नाम पर चर को सबसे छोटे संभव दायरे में घोषित करने की सिफारिश की जाती है (इस उदाहरण में यह लूप के अंदर है, क्योंकि यह एकमात्र स्थान है जहां चर का उपयोग किया जाता है)।


3
यह JVM Soecification का परिणाम है, न कि 'कंपाइलर ऑप्टिमाइज़ेशन'। एक विधि द्वारा आवश्यक स्टैक स्लॉट्स को विधि में प्रवेश पर आवंटित किया जाता है। यह है कि कैसे bytecode निर्दिष्ट किया गया है।
लोर्ने

2
@ इसके अलावा एक और कारण है कि इसे लूप के अंदर रखा जाए (या सिर्फ {{} ’ब्लॉक): कंपाइलर किसी अन्य दायरे में वेरिएबल के लिए स्टैक फ्रेम में आवंटित मेमोरी का फिर से उपयोग करेगा यदि आप उस दूसरे स्कोप में कुछ अधिक होने की घोषणा करते हैं ।
सर्ज

1
यदि इसकी लूपिंग डेटा ऑब्जेक्ट्स की एक सूची के माध्यम से होती है, तो क्या यह डेटा के थोक के लिए कोई फर्क पड़ेगा? शायद ४० हजार।
मिथुन खत्री

7
आप में से किसी के लिए finalप्रेमियों: घोषित करने strके रूप में finalमें insideपैकेज मामला भी कोई फर्क नहीं पड़ता =)
skia.heliou

27

छोटे दायरे में वस्तुओं को घोषित करने से पठनीयता में सुधार होता है

प्रदर्शन आज के संकलक के लिए मायने नहीं रखता। (इस परिदृश्य में)
रखरखाव के दृष्टिकोण से, दूसरा विकल्प बेहतर है।
एक ही जगह पर वैरिएबल को डिक्लेयर और इनिशियलाइज़ करें, संभवत: सबसे कम दायरे में।

जैसा कि डोनाल्ड एर्विन नुथ ने बताया:

"हमें छोटी दक्षता के बारे में भूलना चाहिए, समय के 97% के बारे में कहना चाहिए: समय से पहले अनुकूलन सभी बुराई की जड़ है"

यानी) ऐसी स्थिति जहां एक प्रोग्रामर प्रदर्शन विचारों को कोड के एक टुकड़े के डिजाइन को प्रभावित करता है । इसके परिणामस्वरूप एक ऐसा डिज़ाइन हो सकता है जो उतना साफ नहीं है जितना कि यह हो सकता है या कोड जो कि गलत है, क्योंकि कोड ऑप्टिमाइज़ेशन से जटिल है और प्रोग्रामर ऑप्टिमाइज़ करके विचलित हो जाता है ।


1
"2 वें विकल्प में थोड़ा तेज प्रदर्शन है" => क्या आपने इसे मापा है? एक उत्तर के अनुसार, बायटेकोड एक ही है, इसलिए मुझे नहीं दिखता कि प्रदर्शन अलग कैसे हो सकता है।
8

मुझे खेद है, लेकिन यह वास्तव में एक जावा प्रोग्राम के प्रदर्शन का परीक्षण करने का सही तरीका नहीं है (और आप किसी भी अनंत लूप के प्रदर्शन का परीक्षण कैसे कर सकते हैं?)
assylias

मैं आपके अन्य बिंदुओं से सहमत हूं - यह सिर्फ इतना है कि मेरा मानना ​​है कि कोई प्रदर्शन अंतर नहीं है।
assylias

11

यदि आप strबाहरी लूप का उपयोग करना चाहते हैं; इसे बाहर घोषित करें। अन्यथा, दूसरा संस्करण ठीक है।


11

कृपया अपडेट किए गए उत्तर पर जाएं ...

प्रदर्शन की परवाह करने वालों के लिए System.out को बाहर निकालें और लूप को 1 बाइट तक सीमित करें। डबल (टेस्ट 1/2) और स्ट्रिंग (3/4) का उपयोग करके मिलीसेकंड में बीत चुके समय को विंडोज 7 प्रोफेशनल 64 बिट और जेडीके-1.7.0_21 के साथ नीचे दिया गया है। बाइटकोड (टेस्ट 1 और टेस्ट 2 के लिए भी नीचे दिया गया है) समान नहीं हैं। मैं भी परिवर्तनशील और अपेक्षाकृत जटिल वस्तुओं के साथ परीक्षण करने के लिए बहुत आलसी था।

दोहरा

टेस्ट 1 लिया: 2710 मिसे

टेस्ट 2 ने लिया: 2790 मिसे

स्ट्रिंग (बस परीक्षणों में स्ट्रिंग के साथ डबल बदलें)

टेस्ट 3 लिया: 1200 मिसे

टेस्ट 4 लिया: 3000 मिसे

संकलन और बायटेकोड प्राप्त करना

javac.exe LocalTest1.java

javap.exe -c LocalTest1 > LocalTest1.bc


public class LocalTest1 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        double test;
        for (double i = 0; i < 1000000000; i++) {
            test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }

}

public class LocalTest2 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        for (double i = 0; i < 1000000000; i++) {
            double test = i;
        }
        long finish = System.currentTimeMillis();
        System.out.println("Test1 Took: " + (finish - start) + " msecs");
    }
}


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

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore        5
       7: dload         5
       9: ldc2_w        #3                  // double 1.0E9d
      12: dcmpg
      13: ifge          28
      16: dload         5
      18: dstore_3
      19: dload         5
      21: dconst_1
      22: dadd
      23: dstore        5
      25: goto          7
      28: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      31: lstore        5
      33: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      36: new           #6                  // class java/lang/StringBuilder
      39: dup
      40: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      43: ldc           #8                  // String Test1 Took:
      45: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: lload         5
      50: lload_1
      51: lsub
      52: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      55: ldc           #11                 // String  msecs
      57: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      60: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      63: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: return
}


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

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
       3: lstore_1
       4: dconst_0
       5: dstore_3
       6: dload_3
       7: ldc2_w        #3                  // double 1.0E9d
      10: dcmpg
      11: ifge          24
      14: dload_3
      15: dstore        5
      17: dload_3
      18: dconst_1
      19: dadd
      20: dstore_3
      21: goto          6
      24: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
      27: lstore_3
      28: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: new           #6                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      38: ldc           #8                  // String Test1 Took:
      40: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: lload_3
      44: lload_1
      45: lsub
      46: invokevirtual #10                 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
      49: ldc           #11                 // String  msecs
      51: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

अद्यतन किए गए उत्तर

सभी JVM अनुकूलन के साथ प्रदर्शन की तुलना करना वास्तव में आसान नहीं है। हालांकि, यह कुछ हद तक संभव है। Google कैलीपर में बेहतर परीक्षण और विस्तृत परिणाम

  1. ब्लॉग पर कुछ विवरण: क्या आपको लूप के अंदर या लूप से पहले एक चर घोषित करना चाहिए?
  2. गिटहब भंडार: https://github.com/gunduru/jvdt
  3. दोहरे परिणाम और 100M लूप (और हाँ सभी JVM विवरण) के लिए परीक्षा परिणाम: https://microbenchmarks.appspot.com/runs/b1cef8d1-0e2c-4120-be61-a99faff6bb4

DeclaredBefore 1,759.209 DeclaredInside 2,242.308

  • DeclaredBefore 1,759.209 एनएस
  • घोषणा की गई 2,242.308 एनएस

डबल घोषणा के लिए आंशिक परीक्षण कोड

यह ऊपर दिए गए कोड के समान नहीं है। यदि आप बस एक डमी लूप को कोड करते हैं तो JVM इसे छोड़ देता है, इसलिए आपको कम से कम कुछ असाइन करने और वापस करने की आवश्यकता होती है। कैलिपर प्रलेखन में यह भी सिफारिश की गई है।

@Param int size; // Set automatically by framework, provided in the Main
/**
* Variable is declared inside the loop.
*
* @param reps
* @return
*/
public double timeDeclaredInside(int reps) {
    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Declaration and assignment */
        double test = i;

        /* Dummy assignment to fake JVM */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

/**
* Variable is declared before the loop.
*
* @param reps
* @return
*/
public double timeDeclaredBefore(int reps) {

    /* Dummy variable needed to workaround smart JVM */
    double dummy = 0;

    /* Actual test variable */
    double test = 0;

    /* Test loop */
    for (double i = 0; i <= size; i++) {

        /* Assignment */
        test = i;

        /* Not actually needed here, but we need consistent performance results */
        if(i == size) {
            dummy = test;
        }
    }
    return dummy;
}

सारांश: घोषित किया गया बेहतर प्रदर्शन -सामान्य रूप से छोटे को इंगित करता है- और यह सबसे छोटे दायरे के सिद्धांत के खिलाफ है। जेवीएम को वास्तव में आपके लिए यह करना चाहिए


अमान्य परीक्षण पद्धति, और आप अपने परिणामों की कोई व्याख्या प्रदान नहीं करते हैं।
लोरेन

1
@ ईजेपी यह उन लोगों के लिए बहुत स्पष्ट होना चाहिए जिनके विषय में रुचि है। कार्यप्रणाली को अधिक उपयोगी जानकारी प्रदान करने के लिए PrimosK के उत्तर से लिया गया है। सच कहूं तो मुझे नहीं पता कि इस उत्तर को कैसे सुधारना है, हो सकता है कि आप संपादन पर क्लिक करें और हमें यह दिखा सकें कि इसे ठीक से कैसे करें?
ओनुर गांडुरू

2
1) Java Bytecode रनटाइम पर ऑप्टिमाइज़्ड (रीऑर्डर किया हुआ, ढह गया, आदि) हो जाता है, इसलिए .class फ़ाइलों पर जो लिखा जाता है, उसके बारे में परवाह न करें। 2) 2.8 के प्रदर्शन जीत हासिल करने के लिए 1.000.000.000 रन हैं, इसलिए प्रति रन बनाम सुरक्षित सुरक्षित और उचित प्रोग्रामिंग शैली के बारे में 2.8ns है। मेरे लिए एक स्पष्ट विजेता। 3) चूंकि आप वार्मअप के बारे में कोई जानकारी नहीं देते हैं, इसलिए आपकी टाइमिंग काफी बेकार है।
हार्डकॉन्ड

@ हर्डकोडेड बेहतर परीक्षण / माइक्रो बेंचमार्किंग कैलिपर के साथ केवल डबल और 100 एम लूप के लिए। ऑनलाइन परिणाम, यदि आप चाहते हैं कि अन्य मामलों को संपादित करने के लिए स्वतंत्र महसूस हो।
ओनुर गुंडुरु

धन्यवाद, यह 1) और 3) को समाप्त करता है। लेकिन भले ही समय प्रति चक्र ~ 5ns तक चला गया हो, फिर भी इसे अनदेखा करने का समय है। सिद्धांत में एक छोटी अनुकूलन क्षमता है, वास्तव में आप प्रति चक्र जो सामान कर रहे हैं वह आमतौर पर बहुत अधिक महंगा है। तो कुछ मिनटों या कुछ घंटों के अंतराल में संभावित अधिकतम कुछ सेकंड होगा। उच्च क्षमता उपलब्ध (उदाहरण के लिए कांटा / जुड़ाव, समानांतर धारा) के साथ अन्य विकल्प हैं जो मैं इस तरह के निम्न-स्तर-अनुकूलन पर समय बिताने से पहले जांच करूंगा।
हार्डकॉन्ड

7

इस समस्या का एक समाधान यह हो सकता है कि लूप को घेरते हुए एक चर गुंजाइश प्रदान की जाए:

{
  // all tmp loop variables here ....
  // ....
  String str;
  while(condition){
      str = calculateStr();
      .....
  }
}

बाहरी दायरे के समाप्त होने पर वे स्वचालित रूप से डी-संदर्भ होंगे।



5

यदि आपको strलूप (गुंजाइश से संबंधित) के बाद उपयोग करने की आवश्यकता नहीं है तो दूसरी स्थिति अर्थात

  while(condition){
        String str = calculateStr();
        .....
    }

तब से बेहतर है जब आप स्टैक पर किसी ऑब्जेक्ट को केवल तभी परिभाषित करें जब conditionवह सत्य हो। यानी अगर आपको जरूरत हो तो इसका इस्तेमाल करें


2
ध्यान दें कि पहले संस्करण में भी, कोई वस्तु का निर्माण नहीं किया जाता है, यदि स्थिति झूठी है।
फिलिप वेंडलर

@ फिलिप: हाँ आप सही हैं। मेरी गलती। मैं सोच रहा था कि यह अब क्या है। आपको क्या लगता है?
क्रेटाइलस

1
खैर "स्टैक पर किसी वस्तु को परिभाषित करना" जावा दुनिया में कुछ अजीब शब्द है। इसके अलावा, स्टैक पर एक वैरिएबल आवंटित करना आमतौर पर रनटाइम पर एक नोप होता है, इसलिए परेशान क्यों होता है? प्रोग्रामर की मदद करने के लिए स्कोपिंग असली मुद्दा है।
फिलिप वेंडलर

3

मुझे लगता है कि आपके प्रश्न का उत्तर देने के लिए सबसे अच्छा संसाधन निम्नलिखित पोस्ट होगा:

पहले या पाश में घोषित चर के बीच अंतर?

मेरी समझ के अनुसार यह बात भाषा पर निर्भर होगी। IIRC जावा इसे अनुकूलित करता है, इसलिए इसमें कोई अंतर नहीं है, लेकिन जावास्क्रिप्ट (उदाहरण के लिए) लूप में हर बार पूरी मेमोरी आवंटन करेगा। विशेष रूप से जावा में मुझे लगता है कि प्रोफाइलिंग करते समय दूसरा तेजी से चलेगा।


3

जैसा कि कई लोगों ने बताया है,

String str;
while(condition){
    str = calculateStr();
    .....
}

इससे बेहतर नहीं है:

while(condition){
    String str = calculateStr();
    .....
}

यदि आप इसे पुन: उपयोग नहीं कर रहे हैं, तो उनके स्कोप के बाहर चर घोषित न करें ...


1
शायद इस तरह से छोड़कर: लिंक
Dainius Kreivys

2

वील लूप के बाहर स्ट्रिंग की घोषणा करते हुए इसे लूप के अंदर और बाहर संदर्भित किया जा सकता है। स्ट्रीपिंग स्ट्रिंग लूप के अंदर होने की घोषणा करते हुए इसे केवल लूप के अंदर संदर्भित किया जा सकता है।


1

चर को जहां संभव हो वहां उपयोग किया जाना चाहिए।

यह RAII (संसाधन अधिग्रहण प्रारंभिक है) को आसान बनाता है।

यह वेरिएबल के दायरे को चुस्त-दुरुस्त रखता है। इससे ऑप्टिमाइज़र बेहतर काम करता है।



1

strचर उपलब्ध हो सकता है और जाने के बाद भी, जबकि नीचे दिए गए कोड को मार डाला स्मृति में कुछ जगह सुरक्षित होगा।

 String str;
    while(condition){
        str = calculateStr();
        .....
    }

strचर उपलब्ध नहीं होगा और यह भी स्मृति में जारी किया जाएगा, जिसके लिए आवंटित किया गया था strनीचे दिए गए कोड में चर।

while(condition){
    String str = calculateStr();
    .....
}

यदि हम दूसरे का अनुसरण करते हैं तो निश्चित रूप से यह हमारे सिस्टम मेमोरी को कम करेगा और प्रदर्शन बढ़ाएगा।


0

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


0

सचमुच, ऊपर कहा गया प्रश्न एक प्रोग्रामिंग समस्या है। आप अपने कोड को कैसे प्रोग्राम करना चाहेंगे? आपको एक्सेस करने के लिए 'STR' की आवश्यकता कहाँ है? एक चर घोषित करने का कोई फायदा नहीं है जो स्थानीय रूप से वैश्विक चर के रूप में उपयोग किया जाता है। प्रोग्रामिंग की मूल बातें मुझे विश्वास है।


-1

इन दोनों उदाहरणों का परिणाम एक ही है। हालांकि, पहला आपको strलूप के बाहर चर का उपयोग करने के साथ प्रदान करता है ; दूसरा नहीं है।


-1

इस प्रश्न में लगभग सभी के लिए चेतावनी: यहां नमूना कोड है जहां लूप के अंदर जावा 7 के साथ मेरे कंप्यूटर पर यह आसानी से 200 गुना धीमा हो सकता है (और मेमोरी की खपत भी थोड़ी अलग है)। लेकिन यह आवंटन के बारे में है और न केवल गुंजाइश है।

public class Test
{
    private final static int STUFF_SIZE = 512;
    private final static long LOOP = 10000000l;

    private static class Foo
    {
        private long[] bigStuff = new long[STUFF_SIZE];

        public Foo(long value)
        {
            setValue(value);
        }

        public void setValue(long value)
        {
            // Putting value in a random place.
            bigStuff[(int) (value % STUFF_SIZE)] = value;
        }

        public long getValue()
        {
            // Retrieving whatever value.
            return bigStuff[STUFF_SIZE / 2];
        }
    }

    public static long test1()
    {
        long total = 0;

        for (long i = 0; i < LOOP; i++)
        {
            Foo foo = new Foo(i);
            total += foo.getValue();
        }

        return total;
    }

    public static long test2()
    {
        long total = 0;

        Foo foo = new Foo(0);
        for (long i = 0; i < LOOP; i++)
        {
            foo.setValue(i);
            total += foo.getValue();
        }

        return total;
    }

    public static void main(String[] args)
    {
        long start;

        start = System.currentTimeMillis();
        test1();
        System.out.println(System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        test2();
        System.out.println(System.currentTimeMillis() - start);
    }
}

निष्कर्ष: स्थानीय चर के आकार के आधार पर, अंतर बहुत बड़ा हो सकता है, यहां तक ​​कि बड़े चर भी नहीं।

बस यह कहने के लिए कि कभी-कभी, लूप के बाहर या अंदर क्या होता है।


1
निश्चित रूप से, दूसरा तेज़ है, लेकिन आप अलग-अलग चीजें कर रहे हैं: test1 बड़ी सरणियों के साथ बहुत सारे फू-ऑब्जेक्ट्स बना रहा है, test2 नहीं है। test2 बार-बार उसी Foo ऑब्जेक्ट का पुन: उपयोग कर रहा है, जो बहुपरत वातावरण में खतरनाक हो सकता है।
हार्डकॉन्ड

बहुरंगी वातावरण में खतरनाक ??? कृपया बताएं कि क्यों। हम एक स्थानीय चर के बारे में बात कर रहे हैं। यह विधि के प्रत्येक कॉल पर बनाया गया है।
rt15

यदि आप फू-ऑब्जेक्ट को एक ऑपरेशन में पास करते हैं जो डेटा को अतुल्यकालिक रूप से संसाधित कर रहा है, तो ऑपरेशन अभी भी फू-उदाहरण पर काम कर रहा है जब आप इसमें डेटा बदल रहे हैं। इसके साइड-इफ़ेक्ट होने के लिए मल्टीथ्रेडेड होना भी आवश्यक नहीं है। उदाहरण के लिए पुन: उपयोग करना काफी खतरनाक है, जब आप नहीं जानते कि कौन अभी भी उदाहरण का उपयोग कर रहा है
हार्डकोडेड

Ps: आपका सेटवैल्यू मेथड होना चाहिए bigStuff[(int) (value % STUFF_SIZE)] = value;(2147483649L का मान ट्राई करें)
हार्डकॉन्ड

साइडइफेक्ट्स के बारे में बोलना: क्या आपने अपने तरीकों के परिणामों की तुलना की है?
हार्डकॉन्ड

-1

मुझे लगता है कि वस्तु का आकार भी मायने रखता है। मेरी एक परियोजना में, हमने एक बड़े दो आयामी सरणी की घोषणा की और शुरू की, जो एप्लिकेशन को मेमोरी-आउट अपवाद को फेंक रहा था। हमने इसके बजाय घोषणा को लूप से बाहर कर दिया और हर पुनरावृत्ति की शुरुआत में सरणी को साफ़ कर दिया।


-2

NullPointerExceptionयदि आपकी calculateStr()विधि शून्य हो जाती है, तो आपको जोखिम होता है और फिर आप str पर एक विधि को कॉल करने का प्रयास करते हैं।

अधिक सामान्यतः, एक शून्य मान वाले चर होने से बचें । यह वर्ग विशेषताओं के लिए मजबूत है, वैसे।


2
यह सवाल से संबंधित कोई तरीका नहीं है। NullPointerException (भावी फ़ंक्शन कॉल पर) की संभावना इस बात पर निर्भर नहीं करेगी कि एक चर कैसे घोषित किया जाता है।
डेजर्ट आइस

1
मुझे ऐसा नहीं लगता, क्योंकि सवाल यह है कि "इसे करने का सबसे अच्छा तरीका क्या है?"। IMHO मैं एक सुरक्षित कोड पसंद करेंगे।
रेमी दुलागेहे

1
NullPointerException.यदि इस कोड का प्रयास किया जाता है, तो शून्य जोखिम return str;होता है, जिससे संकलन त्रुटि हो सकती है।
लोर्न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.