2011-04-14 20 views
26

में पूछे जाने पर एक unrelated question जहां मैं इस तरह कोड था:जावा: अगर-रिटर्न-अगर रिटर्न बनाम अगर-रिटर्न-elseif-रिटर्न

public boolean equals(Object obj) 
{ 
    if (this == obj) 
     return true; 

    if (obj == null) 
     return false; 

    if (getClass() != obj.getClass()) 
     return false; 

    // Check property values 
} 

मैं एक टिप्पणी जो दावा किया है कि इस इष्टतम नहीं था हो गया, और (अगर मैं सही ढंग से समझ में आ) यह बजाय कि यह करना चाहिए: क्योंकि वापसी बयान के

public boolean equals(Object obj) 
{ 
    if (this == obj) 
     return true; 

    else if (obj == null) 
     return false; 

    else if (getClass() != obj.getClass()) 
     return false; 

    // Check property values 
} 

, मैं सच में नहीं देख सकते क्यों उनमें से किसी को और अधिक कुशल या अन्य की तुलना में तेजी से किया जाना चाहिए। एक निश्चित वस्तु को देखते हुए, दोनों विधियों को एक समान संख्या में चेक करना होगा जहां तक ​​मैं देख सकता हूं। और वापसी विवरणों के कारण, उनमें से कोई भी अतिरिक्त कोड नहीं चलाया जाएगा।

क्या मुझे यहां कुछ याद आ रही है? क्या इसके लिए कुछ है? क्या कुछ कंपाइलर अनुकूलन या कुछ चल रहा है या जो भी हो?

मुझे पता है कि यह माइक्रो ऑप्टिमाइज़ेशन है और मैं सबसे पहले किसी भी तरह से चिपकने वाला हूं, क्योंकि मुझे लगता है कि यह एक ही स्थिति पर सभी ifs के साथ क्लीनर दिखता है। लेकिन मैं इसकी मदद नहीं कर सकता; मैं उत्सुक हूँ!

+14

मुझे उस व्यक्ति का नाम बताएं जिसने यह टिप्पणी की है और मैं उसे उसके लिए नीचे डाल दूंगा;) –

+3

मैं सलाह देता हूं कि इस तरह के सूक्ष्म स्तर अनुकूलन के बारे में परेशान न करें। आप हमेशा शुद्धियों को विभाजित कर सकते हैं जो बालों को अच्छी तरह विभाजित करते हैं। इस तरह के अनुकूलन को संकलक द्वारा अच्छी तरह से संभाला जाता है और संभावनाएं पहले से ही पहले संस्करण में कम हो जाती हैं (या इसके विपरीत आपके कंपाइलर के विचारों के आधार पर इसके विपरीत)। –

+1

@ जिगार जोशी - आपके हाथ को बढ़ाने के लिए वर्चुअल (+1) :-) –

उत्तर

22

जेनरेट बाइट कोड उन दो मामलों के लिए समान है, इसलिए यह पूरी तरह स्टाइल का मामला है।

मैं दो तरीकों e1 और e2 उत्पादन किया है और दोनों इस बाइट कोड का उत्पादन (javap -v का उपयोग कर पढ़ें):

 
public boolean e1(java.lang.Object); 
    Code: 
    Stack=2, Locals=2, Args_size=2 
    0: aload_0 
    1: aload_1 
    2: if_acmpne 7 
    5: iconst_1 
    6: ireturn 
    7: aload_1 
    8: ifnonnull 13 
    11: iconst_0 
    12: ireturn 
    13: aload_0 
    14: invokevirtual #25; //Method java/lang/Object.getClass:()Ljava/lang/Class; 
    17: aload_1 
    18: invokevirtual #25; //Method java/lang/Object.getClass:()Ljava/lang/Class; 
    21: if_acmpeq 26 
    24: iconst_0 
    25: ireturn 

मैं कोड बाहर छोड़ दिया मुझे लगता है कि के बाद डाल यह संकलन करने के लिए।

+3

@ जिगार: यहां कोई चतुरता नहीं है, संकलक के पास कोई वास्तविक विकल्प नहीं था सभी मामलों के लिए एक ही कोड उत्पन्न करें। बाइट कोड में कोई और 'कथन' नहीं है, केवल 'if-condition-goto' वाले' का एक गुच्छा है। –

+1

केवल एकमात्र चतुरता यह है कि संकलक को यह जानने की ज़रूरत है कि 'ireturn' के बाद इसे' कूद-टू-द-एंड-द-एंड-कैस्केड 'कथन नहीं दिया जाना चाहिए। और यह जांच करने के लिए काफी मामूली है। –

+2

@ जिगार - * "दिलचस्प, कंपाइलर बहुत स्मार्ट है। *" आपको लगता है? आपके लिए न्यूजफ्लैश जिगर। सभी कंपाइलर समय की शुरुआत के बाद से ऐसा कर रहे हैं, क्योंकि तीसरी पीढ़ी के प्रोग्रामिंग भाषाओं का आविष्कार किया गया था (और यहां तक ​​कि लोगों ने असेंबली में मैक्रो निर्देशों का उपयोग शुरू किया था)। लगभग 60 साल पहले आविष्कार संकलक प्रौद्योगिकी में आपका स्वागत है। आपको कंपाइलर तकनीक को जानने की भी आवश्यकता नहीं है। सरल तर्क इन दो सेटों को निर्देशित करता है यदि (और अगर- else) कथन ** ** समकक्ष हैं। –

3

इस तरह से सोचें। जब एक रिटर्न स्टेटमेंट निष्पादित किया जाता है, तो नियंत्रण विधि को छोड़ देता है, इसलिए else वास्तव में कोई मान नहीं जोड़ता है, जब तक कि आप यह तर्क देना नहीं चाहते कि यह पठनीयता को जोड़ता है (जिसे मैं वास्तव में नहीं सोचता हूं, लेकिन अन्य असहमत हो सकते हैं)।

तो आपके पास:

if (someCondition) 
    return 42; 

if (anotherCondition) 
    return 43; 

वास्तव में दूसरे if के लिए एक else जोड़ने में कोई मूल्य नहीं है।

वास्तव में, मैं Resharper नामक सी # कोड लिखते समय एक उपकरण का उपयोग करता हूं, और यह वास्तव में else को इन परिस्थितियों में बेकार कोड के रूप में चिह्नित करेगा। तो मुझे लगता है कि आम तौर पर, उन्हें छोड़ना बेहतर होता है। और जैसा कि जोआचिम ने पहले ही उल्लेख किया है, संकलक उन्हें वैसे भी अनुकूलित करता है।

+2

मैं पूरी तरह से रिशेर्पर से सहमत हूं ... जब मैं ऐसे एल्स देखता हूं, तो मैं उन्हें हटा देता हूं। इसी प्रकार, जब मैं देखता हूं कि क्या (cond) सच हो जाता है तो मैं क्रिंग करता हूं; और झूठी वापसी; ... विश्लेषण के लिए – PhiLho

9

कोई भी दूसरे की तुलना में अधिक कुशल नहीं है। कंपाइलर आसानी से देख सकता है कि दोनों समान हैं, और वास्तव में सन/ओरेकल javac दो विधियों के लिए समान बाइटकोड उत्पन्न करता है।

यहाँ एक IfTest वर्ग है:

class IfTest { 

    public boolean eq1(Object obj) { 
     if (this == obj) 
      return true; 

     if (obj == null) 
      return false; 

     if (getClass() != obj.getClass()) 
      return false; 

     return true; 
    } 


    public boolean eq2(Object obj) { 

     if (this == obj) 
      return true; 

     else if (obj == null) 
      return false; 

     else if (getClass() != obj.getClass()) 
      return false; 

     return true; 
    } 
} 

मैं javac के साथ संकलित और disassembly इस प्रकार है:

public boolean eq1(java.lang.Object); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: if_acmpne 7 
    5: iconst_1 
    6: ireturn 
    7: aload_1 
    8: ifnonnull 13 
    11: iconst_0 
    12: ireturn 
    13: aload_0 
    14: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class; 
    17: aload_1 
    18: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class; 
    21: if_acmpeq 26 
    24: iconst_0 
    25: ireturn 
    26: iconst_1 
    27: ireturn 

 

public boolean eq2(java.lang.Object); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: if_acmpne 7 
    5: iconst_1 
    6: ireturn 
    7: aload_1 
    8: ifnonnull 13 
    11: iconst_0 
    12: ireturn 
    13: aload_0 
    14: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class; 
    17: aload_1 
    18: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class; 
    21: if_acmpeq 26 
    24: iconst_0 
    25: ireturn 
    26: iconst_1 
    27: ireturn 

है कि, मैं सिफारिश करेंगे पहले संस्करण का उपयोग (else के बिना)। कुछ लोग तर्क दे सकते हैं कि यह क्लीनर अन्य भागों के साथ है, लेकिन मैं इसके विपरीत तर्क दूंगा। else समेत इंगित करता है कि प्रोग्रामर को यह एहसास नहीं हुआ कि यह अनावश्यक था।

+0

+1, मैंने पहले से ही प्रश्न के ऊपर एक टिप्पणी में इसे इंगित किया है। यदि आप एकल रिटर्न संस्करण को भी आजमाते हैं तो मुझे विश्वास है कि यह फिर से वही खत्म हो जाएगा - संकलक एक चर बनाने और मेम ऑपरेशन करने की परेशानी के बारे में परेशान नहीं होगा जब यह जानता है कि परिणाम लौटने के लिए यह सब कुछ है। –

+0

दिलचस्प है कि आपके कंपाइलर में 27 का लेन है और @ जोचिम सॉर के कंपाइलर में 25 है। आप किस जेडीके का उपयोग करते थे? – rajah9

+0

मैं सहमत हूं, जिसमें अन्य इंगित करता है कि प्रोग्रामर को यह नहीं पता था कि यह अनावश्यक था। –

5

मुझे किसी भी दिशा में किसी एक कार्यान्वयन को बदलने के लिए कोई व्यावहारिक कारण नहीं दिख रहा है - किसी भी दिशा में।

दूसरा उदाहरण समझ में आता है यदि आप एक विधि में एकाधिक रिटर्न स्टेटमेंट से बचना चाहते हैं - कुछ लोग कोडिंग के उस तरीके को पसंद करते हैं।

public boolean equals(Object obj) 
{ 
    boolean result = true; 

    if (this == obj) 
     result = true; 

    else if (obj == null) 
     result = false; 

    else if (getClass() != obj.getClass()) 
     result = false; 

    return result; 
} 
0

मैं इस कोड एक छोटे से सुधार किया जा सकता है (ध्यान रखें कि आप, यह बहुत पढ़ी जा सकती है):

if (obj == null) 
     return false; 

    if (getClass() != obj.getClass()) 
     return false; 

instanceof ऑपरेटर फिर हम अगर-else if निर्माणों की जरूरत है उन दोनों के बराबर है और संभवतः तेज़ है - कम कोड, और कोई विधि आमंत्रण:

if (!(obj instanceof MyClass)) 
     return false; 

लेकिन मुझे क्या पता है .... मैं बाइट कोड का विश्लेषण करने के लिए बहुत आलसी हूं (इसे पहले कभी नहीं किया है)। :-p

+1

आपको पता होना चाहिए कि 'getClass() 'और' instanceof' * समकक्ष नहीं हैं। यदि आपके पास दो वर्ग 'ए' और' बी' हैं जहां 'बी 'ए' बढ़ाता है, तो 'getClass()' हमेशा' झूठा 'होता है, जबकि 'बी उदाहरण' ए 'सत्य है। – beatngu13

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