जावा में अंतिम कीवर्ड के उपयोग से प्रदर्शन में सुधार होता है?


347

जावा में हम बहुत सारे स्थान देखते हैं जहाँ finalकीवर्ड का उपयोग किया जा सकता है लेकिन इसका उपयोग असामान्य है।

उदाहरण के लिए:

String str = "abc";
System.out.println(str);

उपरोक्त मामले में, strहो सकता है finalलेकिन यह आमतौर पर छोड़ दिया जाता है।

जब कोई विधि कभी भी ओवरराइड नहीं होगी तो हम अंतिम कीवर्ड का उपयोग कर सकते हैं। इसी तरह एक वर्ग के मामले में जो विरासत में नहीं मिलने वाला है।

क्या इनमें से किसी भी या सभी मामलों में अंतिम कीवर्ड का उपयोग वास्तव में प्रदर्शन में सुधार करता है? यदि हां, तो कैसे? कृपया समझाएँ। यदि finalप्रदर्शन के लिए वास्तव में सही उपयोग होता है , तो जावा प्रोग्रामर को कीवर्ड का सर्वोत्तम उपयोग करने के लिए किन आदतों को विकसित करना चाहिए?


मुझे नहीं लगता कि पाल, विधि प्रेषण (कॉल साइट कैशिंग और ...) गतिशील भाषाओं में एक मुद्दा है स्थिर भाषाओं में नहीं
जहान

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

5
मुझे लगा कि यह एक सामान्य परीक्षा का प्रश्न था। मुझे याद है कि अंतिम प्रदर्शन पर प्रभाव पड़ता है, IIRC अंतिम वर्गों को JRE द्वारा किसी तरह से अनुकूलित किया जा सकता है क्योंकि उन्हें उप-वर्गित नहीं किया जा सकता है।
कावू

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

1
"सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है"। बस कंपाइलर को अपना काम करने दें। पठनीय और अच्छी टिप्पणी वाला कोड लिखें। यह हमेशा सबसे अच्छा विकल्प है!
कैसर

जवाबों:


285

आमतौर पर नहीं। वर्चुअल तरीकों के लिए, हॉटस्पॉट इस बात पर नज़र रखता है कि क्या विधि वास्तव में ओवरराइड हो गई है, और इस तरह की धारणा पर इनलाइनिंग के रूप में अनुकूलन करने में सक्षम है कि एक विधि को ओवरराइड नहीं किया गया है - जब तक कि यह एक क्लास को लोड नहीं करता है जो विधि को ओवरराइड करता है, किस बिंदु पर यह उन अनुकूलन को पूर्ववत (या आंशिक रूप से पूर्ववत) कर सकता है।

(बेशक, यह मानकर चल रहे हैं कि आप हॉटस्पॉट का उपयोग कर रहे हैं - लेकिन यह अब तक का सबसे आम जेवीएम है, इसलिए ...)

मेरे दिमाग में आपको finalप्रदर्शन कारणों के बजाय स्पष्ट डिजाइन और पठनीयता के आधार पर उपयोग करना चाहिए । यदि आप प्रदर्शन कारणों से कुछ भी बदलना चाहते हैं, तो आपको स्पष्ट कोड को आकार से बाहर झुकने से पहले उचित माप प्रदर्शन करना चाहिए - इस तरह से आप तय कर सकते हैं कि प्राप्त किया गया कोई अतिरिक्त प्रदर्शन खराब पठनीयता / डिज़ाइन के लायक है या नहीं। (मेरे अनुभव में यह लगभग कभी भी इसके लायक नहीं है; वाईएमएमवी।)

संपादित करें: जैसा कि अंतिम क्षेत्रों का उल्लेख किया गया है, यह स्पष्ट रूप से स्पष्ट डिजाइन के संदर्भ में, वे अक्सर एक अच्छा विचार है। वे क्रॉस-थ्रेड दृश्यता के संदर्भ में गारंटीकृत व्यवहार को भी बदलते हैं: एक कंस्ट्रक्टर पूरा होने के बाद, किसी भी अंतिम फ़ील्ड को तुरंत अन्य थ्रेड्स में दिखाई देने की गारंटी है। यह finalमेरे अनुभव का संभवतः सबसे आम उपयोग है , हालांकि जोश बलोच के "विरासत के लिए डिजाइन या इसे निषेध" नियम के समर्थक के रूप में, मुझे शायद finalकक्षाओं के लिए अधिक बार उपयोग करना चाहिए ...


1
@ अभिषेक: क्या विशेष रूप से के बारे में? सबसे महत्वपूर्ण बिंदु अंतिम एक है - कि आप लगभग निश्चित रूप से इस बारे में चिंता नहीं करनी चाहिए।
जॉन स्कीट

9
@ ऐबिश: finalआमतौर पर सिफारिश की जाती है क्योंकि यह कोड को समझने में आसान बनाता है, और बग को खोजने में मदद करता है (क्योंकि यह प्रोग्रामर्स को स्पष्ट बनाता है)। पीएमडी शायद finalइन शैली मुद्दों के कारण उपयोग करने की सिफारिश करता है, प्रदर्शन के कारणों के लिए नहीं।
हेल्सके

3
@ अभिषेक: इसका बहुत हिस्सा जेवीएम-विशिष्ट होने की संभावना है, और संदर्भ के बहुत सूक्ष्म पहलुओं पर भरोसा कर सकता है। उदाहरण के लिए, मेरा मानना ​​है कि हॉटस्पॉट सर्वर जेवीएम अभी भी एक वर्ग में ओवरराइड होने पर वर्चुअल विधियों की इनलाइनिंग की अनुमति देगा, जहां एक त्वरित प्रकार की जांच जहां उपयुक्त हो। लेकिन विवरण को कम करना मुश्किल है और जारी के बीच अच्छी तरह से बदल सकता है।
जॉन स्कीट

5
यहाँ मैं प्रभावी जावा, द्वितीय संस्करण, आइटम 15, न्यूनतम उत्परिवर्तन को उद्धृत करूंगा Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.:। इसके अलावा An immutable object can be in exactly one state, the state in which it was created.बनाम Mutable objects, on the other hand, can have arbitrarily complex state spaces.। मेरे व्यक्तिगत अनुभव से, कीवर्ड का उपयोग करके finalडेवलपर की मंशा को अपरिवर्तनीयता की ओर झुकाव करना चाहिए, न कि "ऑप्टिमाइज़" कोड। मैं आपको इस अध्याय को पढ़ने के लिए प्रोत्साहित करता हूं, आकर्षक!
लुइस एफ।

2
अन्य जवाबों से पता चलता है कि finalचर पर कीवर्ड का उपयोग करने से बायटेकोड की मात्रा कम हो सकती है, जो प्रदर्शन पर असर डाल सकती है।
जूलियन क्रोनग

86

संक्षिप्त उत्तर: इसके बारे में चिंता मत करो!

लंबा जवाब:

अंतिम स्थानीय चर के बारे में बात करते समय ध्यान रखें कि कीवर्ड का उपयोग finalकरने से कंपाइलर कोड को सांख्यिकीय रूप से अनुकूलित करने में मदद करेगा , जिसके परिणामस्वरूप अंतिम परिणाम तेज कोड हो सकता है। उदाहरण के लिए, a + bनीचे दिए गए उदाहरण में अंतिम स्ट्रिंग्स को सांकेतिक रूप से संक्षिप्त किया जाता है (संकलन समय पर)।

public class FinalTest {

    public static final int N_ITERATIONS = 1000000;

    public static String testFinal() {
        final String a = "a";
        final String b = "b";
        return a + b;
    }

    public static String testNonFinal() {
        String a = "a";
        String b = "b";
        return a + b;
    }

    public static void main(String[] args) {
        long tStart, tElapsed;

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method with finals took " + tElapsed + " ms");

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testNonFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method without finals took " + tElapsed + " ms");

    }

}

परिणाम?

Method with finals took 5 ms
Method without finals took 273 ms

जावा हॉटस्पॉट VM 1.7.0_45-b18 पर परीक्षण किया गया।

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

संकलन-समय एक तरफ लाभ पहुंचाता है, मुझे ऐसा कोई प्रमाण नहीं मिला कि कीवर्ड के उपयोग का finalप्रदर्शन पर कोई औसत दर्जे का प्रभाव हो।


2
मैं 100 बार दोनों मामलों का परीक्षण करने के लिए आपके कोड को फिर से लिखता हूं। आखिरकार फाइनल का औसत समय 0 एमएस और नॉन फाइनल के लिए 9 एमएस था। 10M करने के लिए पुनरावृत्ति गिनती बढ़ाने के लिए औसत 0 एमएस और 75 एमएस निर्धारित किया है। हालांकि, गैर-फाइनल के लिए सबसे अच्छा रन 0 एमएस था। शायद यह वीएम का पता लगाने के परिणाम सिर्फ दूर या कुछ फेंका जा रहा है? मुझे नहीं पता, लेकिन इसकी परवाह किए बिना, फाइनल का उपयोग एक महत्वपूर्ण अंतर बनाता है।
कैस्पर फर्गैंडैंड

5
फूला हुआ परीक्षण। पहले के परीक्षण जेवीएम को गर्म कर देंगे और बाद के टेस्ट इनवोकेशन से लाभान्वित होंगे। अपने परीक्षण फिर से करें और देखें कि क्या होता है। आपको प्रत्येक परीक्षण को अपने स्वयं के JVM उदाहरण में चलाने की आवश्यकता है।
स्टीव कू

16
कोई भी परीक्षण त्रुटिपूर्ण नहीं है, वार्मअप को ध्यान में रखा गया था। दूसरा परीक्षण SLOWER है, तेज नहीं है। वार्मअप के बिना दूसरा परीक्षण ईवीएन SLOWER होगा।
जंग

6
TestFinal () में सभी समय एक ही वस्तु को लौटाते हैं, स्ट्रिंग्स पूल से, क्योंकि अंतिम स्ट्रिंग्स और स्ट्रिंग्स शाब्दिक संघटन के पुनरावर्तन का संकलन समय पर मूल्यांकन किया जाता है। testNonFinal () हर बार नई वस्तु लौटाता है, यानी गति में अंतर समझाता है।
अंबर

4
क्या आपको लगता है कि परिदृश्य अवास्तविक है? Stringजोड़ से ज्यादा महंगा ऑपरेशन है Integers। इसे सांख्यिकीय रूप से करना (यदि संभव हो) अधिक कुशल है, यही परीक्षण दिखाता है।
रस्टीक्स

62

हाँ यह कर सकते हैं। यहाँ एक उदाहरण है जहाँ अंतिम प्रदर्शन को बढ़ावा दे सकता है:

सशर्त संकलन एक ऐसी तकनीक है जिसमें किसी विशेष स्थिति के आधार पर कोड की पंक्तियों को वर्ग फ़ाइल में संकलित नहीं किया जाता है। इसका उपयोग उत्पादन निर्माण में टन डिबगिंग कोड को हटाने के लिए किया जा सकता है।

निम्नलिखित को धयान मे रखते हुए:

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (doSomething) {
       // do first part. 
    }

    if (doSomething) {
     // do second part. 
    }

    if (doSomething) {     
      // do third part. 
    }

    if (doSomething) {
    // do finalization part. 
    }
}

DoSomething विशेषता को अंतिम विशेषता में परिवर्तित करके, आपने संकलक को बताया है कि जब भी वह doSomething को देखता है, तो उसे संकलन-समय प्रतिस्थापन नियमों के अनुसार इसे गलत के साथ प्रतिस्थापित करना चाहिए। कंपाइलर का पहला पास कोड को कुछ इस तरह बदलता है :

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (false){
       // do first part. 
    }

    if (false){
     // do second part. 
    }

    if (false){
      // do third part. 
    }

    if (false){
    // do finalization part. 

    }
}

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

public class ConditionalCompile {


  private final static boolean doSomething= false;

  public static void someMethodBetter( ) {

    // do first part. 

    // do second part. 

    // do third part. 

    // do finalization part. 

  }
}

इस प्रकार किसी भी अत्यधिक कोड, या किसी भी अनावश्यक सशर्त जाँच को कम करना।

संपादित करें: एक उदाहरण के रूप में, चलो निम्नलिखित कोड लेते हैं:

public class Test {
    public static final void main(String[] args) {
        boolean x = false;
        if (x) {
            System.out.println("x");
        }
        final boolean y = false;
        if (y) {
            System.out.println("y");
        }
        if (false) {
            System.out.println("z");
        }
    }
}

जावा 8 के साथ इस कोड को संकलित करते समय और javap -c Test.classहमारे साथ डिकम्पाइल करने पर:

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

  public static final void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: ifeq          14
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #22                 // String x
      11: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: iconst_0
      15: istore_2
      16: return
}

हम ध्यान दें कि संकलित कोड में केवल गैर-अंतिम चर शामिल है x। यह मानता है कि अंतिम चर का प्रदर्शन पर प्रभाव पड़ता है, कम से कम इस साधारण मामले के लिए।


1
@ AnukaszLech मैंने अंतिम कीवर्ड के बारे में अपने अध्याय पर एक कट्टर पुस्तक: हार्डकोर जावा से यह सीखा।
mel3kings

15
यह संकलन समय पर अनुकूलन के बारे में बात करता है, इसका मतलब है कि डेवलपर को संकलन समय पर अंतिम बूलियन चर का मूल्य पता है, लेखन का पूरा बिंदु क्या है यदि पहली जगह में ब्लॉक होता है तो इस परिदृश्य के लिए जहां IF-CONDITIONS आवश्यक नहीं हैं और नहीं बना रहे हैं कोई मतलब? मेरी राय में, भले ही यह प्रदर्शन को बढ़ाता है, यह पहली जगह में गलत कोड है और इसे संकलक को जिम्मेदारी पारित करने के बजाय खुद डेवलपर द्वारा अनुकूलित किया जा सकता है और प्रश्न मुख्य रूप से सामान्य कोड में प्रदर्शन सुधार के बारे में पूछना चाहता है जहां अंतिम का उपयोग किया जाता है प्रोग्रामेटिक अर्थ बनाता है।
भावेश अग्रवाल

7
इसका मतलब यह होगा कि डिबगिंग स्टेटमेंट्स को मेल 3kings कहा जाए। आप उत्पादन के निर्माण से पहले चर को फ्लिप कर सकते हैं (या इसे अपनी बिल्ड स्क्रिप्ट में कॉन्फ़िगर कर सकते हैं) और वितरण बनने पर स्वचालित रूप से उस कोड को हटा दें।
एडम

37

आईबीएम के अनुसार - यह कक्षाओं या विधियों के लिए नहीं है।

http://www.ibm.com/developerworks/java/library/j-jtp04223.html


1
... और आईबीएम के अनुसार, यह खेतों के लिए करता है : ibm.com/developerworks/java/library/j-jtp1029/… - और इसे एक सर्वोत्तम अभ्यास के रूप में भी प्रचारित किया जाता है।
फिल्पन

2
लेख "04223" वर्ष 2003 से है। अब लगभग सत्रह साल पुराना है। वह था ... जावा 1.4?
दैत्यराज

16

मैं चकित हूं कि किसी ने वास्तव में कुछ वास्तविक कोड पोस्ट नहीं किए हैं जो यह साबित करने के लिए डी-संकलित हैं कि कम से कम कुछ मामूली अंतर है।

संदर्भ के लिए यह javacसंस्करण के खिलाफ परीक्षण किया गया है 8, 9और 10

इस विधि को मानें:

public static int test() {
    /* final */ Object left = new Object();
    Object right = new Object();

    return left.hashCode() + right.hashCode();
}

इस कोड को इस रूप में संकलित करना, ठीक उसी बाइट कोड का उत्पादन करता है जब finalवह मौजूद था ( final Object left = new Object();)।

लेकिन यह एक:

public static int test() {
    /* final */ int left = 11;
    int right = 12;
    return left + right;
}

पैदा करता है:

   0: bipush        11
   2: istore_0
   3: bipush        12
   5: istore_1
   6: iload_0
   7: iload_1
   8: iadd
   9: ireturn

finalउपस्थित होने के लिए छोड़कर :

   0: bipush        12
   2: istore_1
   3: bipush        11
   5: iload_1
   6: iadd
   7: ireturn

कोड बहुत अधिक आत्म-व्याख्यात्मक है, यदि कोई संकलन समय स्थिर है, तो इसे सीधे ऑपरेंड स्टैक पर लोड किया जाएगा (इसे स्थानीय चर सरणी में संग्रहीत नहीं किया जाएगा जैसे पिछले उदाहरण के माध्यम से होता है bipush 12; istore_0; iload_0 ) - किस तरह का अर्थ है चूंकि कोई भी इसे बदल नहीं सकता है।

दूसरी ओर क्यों दूसरे मामले में संकलक उत्पादन नहीं करता istore_0 ... iload_0है मेरे से परे है, यह उस स्लॉट की तरह नहीं है0 किसी भी तरह से का उपयोग किया जाता है (यह चर सरणी को इस तरह से सिकोड़ सकता है, लेकिन हो सकता है कि मुझे कुछ आंतरिक विवरण याद आ रहे हों, नहीं। पक्का बताइए)

मैं इस तरह के अनुकूलन को देखकर आश्चर्यचकित था, यह देखते हुए कि छोटे लोग कैसे करते हैं javac। जैसा कि हम हमेशा उपयोग करना चाहिए final? मैं एक JMHपरीक्षण लिखने के लिए भी नहीं जा रहा हूं (जो मैं शुरू में चाहता था), मुझे यकीन है कि अंतर के क्रम में है ns(यदि संभव हो तो सभी पर कब्जा कर लिया जाए)। एकमात्र स्थान यह एक समस्या हो सकती है, यह तब है जब किसी विधि को आकार के कारण इनलेट नहीं किया जा सकता है (और finalकुछ बाइट्स द्वारा उस आकार को छोटा करने की घोषणा करना)।

दो और finalएस हैं जिन्हें संबोधित करने की आवश्यकता है। पहला तरीका है जब एक विधि final(एक JITदृष्टिकोण से), इस तरह की एक विधि मोनोमोर्फिक है - और ये सबसे प्यारे हैं JVM

फिर finalउदाहरण चर हैं (जो प्रत्येक निर्माणकर्ता में सेट होने चाहिए); ये महत्वपूर्ण हैं क्योंकि वे एक सही ढंग से प्रकाशित संदर्भ की गारंटी देंगे, जैसा कि यहां थोड़ा सा छुआ है और इसके द्वारा भी निर्दिष्ट किया गया है JLS


मैंने डिबग विकल्प () के साथ जावा 8 (JDK 1.8.0_162) का उपयोग करके कोड संकलित किया javac -g FinalTest.java, javap -c FinalTest.classऔर उपयोग करने वाले कोड को विघटित किया और उसी परिणाम को प्राप्त नहीं किया (साथ final int left=12, मुझे मिला bipush 11; istore_0; bipush 12; istore_1; bipush 11; iload_1; iadd; ireturn)। तो हाँ, बहुत सारे कारकों पर उत्पन्न बायोटेक आश्रितों और यह कहना मुश्किल है कि finalप्रदर्शन पर कोई प्रभाव पड़ता है या नहीं। लेकिन जैसे ही बाइटकोड अलग होता है, कुछ प्रदर्शन अंतर मौजूद हो सकते हैं।
जुलिएन क्रोनगैस


13

आप वास्तव में दो (कम से कम) विभिन्न मामलों के बारे में पूछ रहे हैं:

  1. final स्थानीय चरों के लिए
  2. final तरीकों / कक्षाओं के लिए

जॉन स्कीट पहले ही 2 जवाब दे चुका है)। लगभग 1):

मुझे नहीं लगता कि इससे कोई फर्क पड़ता है; स्थानीय चरों के लिए, कंपाइलर यह डिसाइड कर सकता है कि वेरिएबल फाइनल है या नहीं (बस यह चेक करके कि यह एक से अधिक बार असाइन किया गया है)। इसलिए यदि संकलक उन चर का अनुकूलन करना चाहता है जो केवल एक बार असाइन किए गए हैं, तो यह कोई फर्क नहीं पड़ता कि चर वास्तव में घोषित किया गया है finalया नहीं।

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

सारांश में, मुझे कोई कारण नहीं दिखाई देता कि इसे प्रदर्शन में मदद क्यों करनी चाहिए। इसलिए इस तरह के माइक्रो-ऑप्टिमाइज़ेशन से मदद मिलने की संभावना नहीं है। आप यह सुनिश्चित करने के लिए बेंचमार्किंग की कोशिश कर सकते हैं, लेकिन मुझे संदेह है कि इससे फर्क पड़ेगा।

संपादित करें:

दरअसल, टिमो वेस्टकमर के जवाब के मुताबिक, कुछ मामलों में क्लास फील्ड के लिए प्रदर्शन में सुधार final कर सकते हैं। मुझे सही साबित होना है।


मुझे नहीं लगता कि कंपाइलर एक स्थानीय चर को कितनी बार असाइन किया गया है, सही ढंग से जांच कर सकता है: यदि कई असाइनमेंट के साथ तत्कालीन-और संरचनाएं क्या हैं?
ग्यूर्ग्याभराम् २०'१३

1
@gyabraham: कंपाइलर पहले से ही ऐसे मामलों की जाँच करता है यदि आप एक स्थानीय चर घोषित करते हैं final, तो यह सुनिश्चित करने के लिए कि आप दो बार असाइन नहीं करते हैं। जहाँ तक मैं देख सकता हूँ, वही जाँच तर्क हो सकता है (और शायद है) जाँच के लिए प्रयोग किया जाता है कि क्या एक चर हो सकता है final
13

एक स्थानीय चर के अंतिम-नेस को बाइटकोड में व्यक्त नहीं किया जाता है, इस प्रकार जेवीएम को यह भी पता नहीं है कि यह अंतिम था
स्टीव कू

1
@SteveKuo: भले ही इसे बाईटेकोड में व्यक्त नहीं किया गया है, यह javacबेहतर अनुकूलन करने में मदद कर सकता है। लेकिन यह सिर्फ अटकलें हैं।
साल्सेक

1
कंपाइलर यह पता लगा सकता है कि क्या एक स्थानीय चर को एक बार ठीक से सौंपा गया है, लेकिन व्यवहार में, यह (त्रुटि जाँच से परे) नहीं है। दूसरी ओर, यदि एक finalचर एक आदिम प्रकार या प्रकार का है Stringऔर तुरंत संकलन-समय स्थिरांक के साथ सौंपा गया है जैसे प्रश्न के उदाहरण में, संकलक को इनलाइन करना चाहिए , क्योंकि चर प्रति विनिर्देशन संकलन-समय स्थिर है। लेकिन अधिकांश उपयोग के मामलों के लिए, कोड अलग-अलग दिख सकता है, लेकिन यह अभी भी कोई फर्क नहीं पड़ता है कि क्या स्थिरांक एक स्थानीय चर प्रदर्शन-वार से अंतःस्थापित है या पढ़ा गया है।
होल्गर

6

नोट: जावा विशेषज्ञ नहीं

अगर मुझे अपना जावा सही से याद है, तो अंतिम कीवर्ड का उपयोग करके प्रदर्शन में सुधार करने का बहुत कम तरीका होगा। मैंने हमेशा इसे "अच्छे कोड" के लिए अस्तित्व में जाना है - डिजाइन और पठनीयता।


1

मैं एक विशेषज्ञ नहीं हूं, लेकिन मुझे लगता है कि अगर आप को finalओवरराइट नहीं किया जाएगा और केवल चरों को छोड़ दें तो आपको कक्षा या विधि में कीवर्ड जोड़ना चाहिए । अगर ऐसी चीजों को अनुकूलित करने का कोई तरीका होगा, तो कंपाइलर आपके लिए ऐसा करेगा।


1

दरअसल, कुछ ओपन-संबंधित कोड का परीक्षण करते समय, मैंने पाया कि एक निजी क्षेत्र पर अंतिम संशोधक का उपयोग प्रदर्शन को नीचा कर सकता है । यहाँ उस कक्षा की शुरुआत है जिसका मैंने परीक्षण किया था:

public class ShaderInput {

    private /* final */ float[] input;
    private /* final */ int[] strides;


    public ShaderInput()
    {
        this.input = new float[10];
        this.strides = new int[] { 0, 4, 8 };
    }


    public ShaderInput x(int stride, float val)
    {
        input[strides[stride] + 0] = val;
        return this;
    }

    // more stuff ...

और यह वह विधि है जिसका उपयोग मैंने विभिन्न विकल्पों के प्रदर्शन का परीक्षण करने के लिए किया, जिनमें से ShaderInput वर्ग:

public static void test4()
{
    int arraySize = 10;
    float[] fb = new float[arraySize];
    for (int i = 0; i < arraySize; i++) {
        fb[i] = random.nextFloat();
    }
    int times = 1000000000;
    for (int i = 0; i < 10; ++i) {
        floatVectorTest(times, fb);
        arrayCopyTest(times, fb);
        shaderInputTest(times, fb);
        directFloatArrayTest(times, fb);
        System.out.println();
        System.gc();
    }
}

तीसरे पुनरावृत्ति के बाद, वीएम गर्म हो गया, मुझे लगातार अंतिम कुंजी शब्द के बिना ये आंकड़े मिले :

Simple array copy took   : 02.64
System.arrayCopy took    : 03.20
ShaderInput took         : 00.77
Unsafe float array took  : 05.47

साथ अंतिम कीवर्ड:

Simple array copy took   : 02.66
System.arrayCopy took    : 03.20
ShaderInput took         : 02.59
Unsafe float array took  : 06.24

ShaderInput परीक्षण के आंकड़ों पर ध्यान दें।

इससे कोई फ़र्क नहीं पड़ा कि मैंने खेतों को सार्वजनिक किया है या निजी।

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

इसके अलावा System.arrayCopy वास्तव में एक सरणी से दूसरे लूप में तत्वों को कॉपी करने की तुलना में छोटे सरणियों के लिए वास्तव में कुछ धीमा है। और sun.misc.Unsafe (साथ ही प्रत्यक्ष java.nio.FloatBuffer, यहां नहीं दिखाया गया है) का उपयोग करते हुए संक्षिप्त प्रदर्शन करता है।


1
आप मापदंडों को अंतिम बनाना भूल गए। <pre> <code> public ShaderInput x (अंतिम int stride, final float val) {इनपुट [strides [stride] + 0] = val; इसे वापस करो; } </ code> </ pre> मेरे अनुभवों में, कोई भी चर या क्षेत्र फाइनल करना वास्तव में प्रदर्शन को बढ़ा सकता है।
एंटिको

1
ओह, और दूसरों को भी फाइनल करें: <pre> <code> अंतिम int arraySize = 10; अंतिम फ्लोट [] fb = new float [arraySize]; for (int i = 0; i <arraySize; i ++) {fb [i] = random.nextFloat (); } अंतिम इंट समय = 1000000000; for (int i = 0; i <10; ++ i) {floatVectorTest (times, fb); arrayCopyTest (बार, एफबी); shaderInputTest (बार, fb); directFloatArrayTest (बार, एफबी); Println (); System.gc (); } </ code> </ pre>
एंटिक्रो

1

अंतिम (कम से कम सदस्य चर और मापदंडों के लिए) मनुष्यों के लिए अधिक है तो यह मशीन के लिए है।

जहाँ भी संभव हो, चर को अंतिम रूप देना अच्छा अभ्यास है। काश जावा ने डिफ़ॉल्ट रूप से "चर" को अंतिम बना दिया होता और परिवर्तन की अनुमति देने के लिए "म्यूटेबल" कीवर्ड होता। अपरिवर्तनीय कक्षाएं बहुत बेहतर थ्रेडेड कोड की ओर ले जाती हैं, और प्रत्येक सदस्य के सामने "अंतिम" के साथ एक कक्षा में सिर्फ glancing जल्दी से अपरिवर्तनीय दिखाएगा।

एक और मामला - मैं @ NonNull / @ Nullable एनोटेशन का उपयोग करने के लिए बहुत सारे कोड को परिवर्तित कर रहा हूं (आप कह सकते हैं कि एक विधि पैरामीटर को अशक्त नहीं होना चाहिए फिर IDE आपको हर उस स्थान को चेतावनी दे सकता है जो आप एक चर पास करते हैं जो @ टैग नहीं किया गया है @ NonNull - पूरी बात एक हास्यास्पद डिग्री तक फैलती है)। किसी सदस्य चर या पैरामीटर को साबित करना बहुत आसान है, जब इसे अंतिम रूप से टैग किया जाता है, तो यह शून्य नहीं हो सकता क्योंकि आपको पता है कि इसे कहीं और नहीं सौंपा जा रहा है।

मेरा सुझाव डिफ़ॉल्ट रूप से सदस्यों और मापदंडों के लिए अंतिम रूप से आवेदन करने की आदत में आना है, यह सिर्फ कुछ ही अक्षर हैं, लेकिन कुछ और नहीं तो अपनी कोडिंग शैली को सुधारने की दिशा में आपको प्रेरित करेंगे।

विधियों या कक्षाओं के लिए अंतिम एक और अवधारणा है क्योंकि यह पुन: उपयोग के एक बहुत ही मान्य रूप को अस्वीकार करता है और वास्तव में पाठक को बहुत कुछ नहीं बताता है। सबसे अच्छा उपयोग संभवत: जिस तरह से उन्होंने स्ट्रिंग और अन्य आंतरिक प्रकार के फाइनल किए हैं ताकि आप हर जगह सुसंगत व्यवहार पर भरोसा कर सकें - कि बहुत सारे कीड़े रोका (हालांकि कई बार मुझे स्ट्रिंग का विस्तार करने के लिए प्यार होता है .... ओह संभावनाओं)


0

जैसा कि कहीं और उल्लेख किया गया है, एक स्थानीय चर के लिए 'अंतिम', और कुछ हद तक एक सदस्य चर, शैली का एक मामला अधिक है।

'अंतिम' एक ऐसा कथन है जिसे आप परिवर्तन नहीं करने का इरादा रखते हैं (यानी, चर भिन्न नहीं होगा!)। कंपाइलर आपकी शिकायत करने में आपकी मदद कर सकता है यदि आप अपने स्वयं के बाधा का उल्लंघन करते हैं।

मैं इस भावना को साझा करता हूं कि यदि पहचानकर्ता हैं तो जावा एक बेहतर भाषा होगी (मुझे क्षमा करें, मैं बस एक गैर-भिन्न चीज को 'चर' नहीं कह सकता) डिफ़ॉल्ट रूप से अंतिम थी, और आपको स्पष्ट रूप से यह कहने की आवश्यकता थी कि वे चर थे। लेकिन यह कहते हुए कि, मैं आमतौर पर ऐसे स्थानीय चर पर 'अंतिम' का उपयोग नहीं करता, जो आरंभिक हैं और जिन्हें कभी सौंपा नहीं गया है; यह सिर्फ शोर लगता है।

(मैं सदस्य चर पर अंतिम उपयोग करता हूं)


-3

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


2
यह कैसी बकवास है? क्या आपके पास कोई स्रोत है जो आपको लगता है कि यह मामला है?
जे। डो

-4

final जावा में कीवर्ड को पांच तरीकों से इस्तेमाल किया जा सकता है।

  1. एक वर्ग अंतिम है
  2. एक संदर्भ चर अंतिम है
  3. एक स्थानीय चर अंतिम है
  4. एक विधि अंतिम है

एक वर्ग अंतिम है: एक वर्ग अंतिम है जिसका अर्थ है कि हम बढ़ाया नहीं जा सकता है या वंशानुक्रम का अर्थ है वंशानुक्रम संभव नहीं है।

इसी प्रकार - एक वस्तु अंतिम है: कुछ समय हमने वस्तु की आंतरिक स्थिति को संशोधित नहीं किया है, इसलिए ऐसे मामले में हम निर्दिष्ट कर सकते हैं कि वस्तु अंतिम वस्तु है। अंतिम अंतिम का मतलब है चर भी अंतिम नहीं है।

एक बार जब संदर्भ चर को अंतिम बना दिया जाता है, तो इसे अन्य ऑब्जेक्ट पर पुन: असाइन नहीं किया जा सकता है। लेकिन वस्तु की सामग्री को तब तक बदल सकते हैं जब तक कि उसके क्षेत्र अंतिम न हों


2
"ऑब्जेक्ट अंतिम है" से आपका मतलब है "ऑब्जेक्ट अपरिवर्तनीय है"।
gyorgyabraham

6
आप सही हैं, लेकिन आप सवाल का जवाब नहीं दे रहे हैं। ओपी ने यह नहीं पूछा कि क्या finalमतलब है, लेकिन क्या finalप्रदर्शन को प्रभावित करना।
होन्जा ज़िदेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.