जावा 8 डिफ़ॉल्ट तरीके लक्षण के रूप में: सुरक्षित?


116

क्या जावा 8 में एक गरीब आदमी के लक्षण के रूप में डिफ़ॉल्ट विधियों का उपयोग करना एक सुरक्षित अभ्यास है ?

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

मेरे पास निम्नलिखित व्यावहारिक उपयोग मामला है:

public interface Loggable {
    default Logger logger() {
        return LoggerFactory.getLogger(this.getClass());
    }
}

या शायद, परिभाषित करें PeriodTrait:

public interface PeriodeTrait {
    Date getStartDate();
    Date getEndDate();
    default isValid(Date atDate) {
        ...
    }
}

जाहिर है, रचना का उपयोग किया जा सकता है (या यहां तक ​​कि सहायक वर्ग) लेकिन यह अधिक क्रियात्मक और अव्यवस्थित लगता है और बहुरूपता से लाभ उठाने की अनुमति नहीं देता है।

तो, क्या मूलभूत लक्षणों के रूप में डिफ़ॉल्ट विधियों का उपयोग करना ठीक है / सुरक्षित है , या क्या मुझे अप्रत्याशित दुष्प्रभावों के बारे में चिंतित होना चाहिए?

SO पर कई प्रश्न जावा बनाम स्काला लक्षण से संबंधित हैं; यहाँ वह बात नहीं है। मैं केवल राय के लिए नहीं पूछ रहा हूँ। इसके बजाय, मैं एक आधिकारिक जवाब या कम से कम क्षेत्र अंतर्दृष्टि की तलाश कर रहा हूं: यदि आपने अपने कॉर्पोरेट प्रोजेक्ट पर लक्षण के रूप में डिफ़ॉल्ट विधियों का उपयोग किया है, तो क्या यह टाइमबॉम्ब निकला?


यह मुझे लगता है कि आप एक सार वर्ग को प्राप्त करने से समान लाभ प्राप्त कर सकते हैं और पंडों को रोने के बारे में चिंता करने की ज़रूरत नहीं है ... एकमात्र कारण मैं एक इंटरफ़ेस में एक डिफ़ॉल्ट विधि का उपयोग करने के लिए देख सकता हूं कि आपको कार्यक्षमता की आवश्यकता है और नहीं कर सकते इंटरफ़ेस पर आधारित विरासत कोड का एक गुच्छा संशोधित करें।
डेवेन फिलिप्स

1
मैं एक सार वर्ग का विस्तार करने के बारे में @ infosec812 से सहमत हूं जो अपने स्वयं के स्थिर लकड़हारे क्षेत्र को परिभाषित करता है। क्या आपका लकड़हारा () विधि हर बार एक नए लकड़हारा उदाहरण को तुरंत नहीं बुलाएगा?
Eidan Spiegel

लॉगिंग के लिए, आप Projectlombok.org और उनके @ Slf4j एनोटेशन को देखना चाह सकते हैं।
डेव फिलिप्स

जवाबों:


120

संक्षिप्त उत्तर है: यदि आप उन्हें सुरक्षित रूप से उपयोग करते हैं तो यह सुरक्षित है :)

कर्कश उत्तर: मुझे बताएं कि आपके लक्षणों का क्या मतलब है, और शायद मैं आपको बेहतर उत्तर दूंगा :)

सभी गंभीरता में, शब्द "विशेषता" अच्छी तरह से परिभाषित नहीं है। कई जावा डेवलपर्स सबसे अधिक लक्षणों से परिचित हैं क्योंकि वे स्काला में व्यक्त किए गए हैं, लेकिन स्काला पहली भाषा से दूर या तो नाम या प्रभाव में है।

उदाहरण के लिए, स्काला में, लक्षण स्टेटफुल ( varचर हो सकते हैं ); किले में वे शुद्ध व्यवहार करते हैं। डिफ़ॉल्ट विधियों के साथ जावा के इंटरफेस स्टेटलेस हैं; इसका मतलब यह है कि वे लक्षण नहीं हैं? (संकेत: यह एक ट्रिक प्रश्न था।)

फिर, स्काला में, रेखीयकरण के माध्यम से लक्षणों की रचना की जाती है; वर्ग अगर Aलक्षण फैली Xऔर Y, फिर जिस क्रम में Xऔर Yनिर्धारित करता है में मिलाया जाता है कैसे के बीच संघर्ष Xऔर Yहल कर रहे हैं। जावा में, यह रैखिककरण तंत्र मौजूद नहीं है (इसे अस्वीकार कर दिया गया था, भाग में, क्योंकि यह "संयुक्त राष्ट्र-जावा-जैसा था)" था।

इंटरफेस में डिफ़ॉल्ट तरीकों को जोड़ने के लिए अनुमानित कारण इंटरफ़ेस विकास का समर्थन करना था , लेकिन हम अच्छी तरह से जानते थे कि हम इससे परे जा रहे थे। क्या आप समझते हैं कि "इंटरफ़ेस विकास ++" या "लक्षण -" होना व्यक्तिगत व्याख्या का विषय है। इसलिए, सुरक्षा के बारे में आपके प्रश्न का उत्तर देने के लिए ... इसलिए जब तक आप वास्तव में तंत्र का समर्थन करते हैं, तब तक यह इच्छा करने की कोशिश करने के बजाय कि यह किसी चीज़ का समर्थन नहीं करता है, आपको ठीक होना चाहिए।

एक प्रमुख डिजाइन लक्ष्य यह था कि एक इंटरफ़ेस के क्लाइंट के दृष्टिकोण से , डिफ़ॉल्ट तरीकों को "नियमित" इंटरफ़ेस विधियों से अप्रभेद्य होना चाहिए। एक विधि का डिफ़ॉल्ट-नेस, इसलिए इंटरफ़ेस के डिजाइनर और कार्यान्वयन के लिए केवल दिलचस्प है ।

यहाँ कुछ उपयोग के मामले हैं जो डिज़ाइन लक्ष्यों के लिए ठीक हैं:

  • इंटरफ़ेस विकास। यहां, हम मौजूदा इंटरफ़ेस में एक नई विधि जोड़ रहे हैं, जिसमें उस इंटरफ़ेस पर मौजूदा विधियों के संदर्भ में एक समझदार डिफ़ॉल्ट कार्यान्वयन है। एक उदाहरण forEachविधि को जोड़ना होगा Collection, जहां iterator()विधि के संदर्भ में डिफ़ॉल्ट कार्यान्वयन लिखा जाता है ।

  • "वैकल्पिक" तरीके। यहां, एक इंटरफ़ेस का डिज़ाइनर कह रहा है "कार्यान्वयनकर्ताओं को इस पद्धति को लागू करने की आवश्यकता नहीं है यदि वे कार्यक्षमता में सीमाओं के साथ रहने के लिए तैयार हैं जो प्रवेश करते हैं"। उदाहरण के लिए, Iterator.removeएक डिफ़ॉल्ट दिया गया था जो फेंकता है UnsupportedOperationException; Iteratorइस व्यवहार के कार्यान्वयन के विशाल बहुमत के बाद से , डिफ़ॉल्ट रूप से इस पद्धति को अनिवार्य रूप से वैकल्पिक बनाता है। (यदि इससे होने वाले व्यवहार AbstractCollectionको चूक के रूप में व्यक्त किया गया था Collection, तो हम पारस्परिक तरीकों के लिए भी ऐसा कर सकते हैं।)

  • सुविधा के तरीके। ये ऐसी विधियाँ हैं जो कड़ाई से सुविधा के लिए हैं, फिर से आम तौर पर वर्ग पर गैर-डिफ़ॉल्ट विधियों के रूप में लागू की जाती हैं। logger()आपके पहले उदाहरण में विधि इस का एक उचित चित्रण है।

  • Combinators। ये संरचनात्मक विधियाँ हैं जो वर्तमान उदाहरण के आधार पर इंटरफ़ेस के नए उदाहरणों को त्वरित करती हैं। उदाहरण के लिए, तरीके Predicate.and()या Comparator.thenComparing()संयोजन के उदाहरण हैं।

यदि आप एक डिफ़ॉल्ट कार्यान्वयन प्रदान करते हैं, तो आपको डिफ़ॉल्ट के लिए कुछ विनिर्देश प्रदान करना चाहिए (JDK में, हम इसके लिए @implSpecjavadoc टैग का उपयोग करते हैं ) कार्यान्वयनकर्ताओं को यह समझने में सहायता करने के लिए कि वे विधि को ओवरराइड करना चाहते हैं या नहीं। कुछ चूक, जैसे सुविधा के तरीके और कॉम्बिनेटर, लगभग कभी भी ओवरराइड नहीं होते हैं; अन्य, वैकल्पिक तरीकों की तरह, अक्सर ओवरराइड होते हैं। आपको डिफ़ॉल्ट का वादा करने के लिए पर्याप्त विनिर्देश (न केवल प्रलेखन) प्रदान करने की आवश्यकता है, इसलिए कार्यान्वयनकर्ता इस बारे में एक समझदार निर्णय ले सकता है कि क्या उन्हें इसे ओवरराइड करने की आवश्यकता है।


9
इस व्यापक उत्तर के लिए धन्यवाद ब्रायन। अब मैं एक हल्के दिल के साथ डिफ़ॉल्ट तरीकों का उपयोग कर सकता हूं। पाठकों: इंटरफ़ेस विकास और डिफ़ॉल्ट तरीकों पर ब्रायन गोएट्ज से अधिक जानकारी उदाहरण के लिए नाइटहैकिंग वर्ल्डवाइड लैम्बडा में पाई जा सकती है ।
youri

धन्यवाद @ ब्रायन-गोएत्ज़ आपने जो कहा है, उससे मुझे लगता है कि जावा के डिफ़ॉल्ट तरीके पारंपरिक लक्षणों की धारणा के करीब हैं, जैसे कि डुकासे एट अल पेपर ( scg.unibe.ch/archive/papers/Duca06bTOPLLraits.pdf ) में परिभाषित किया गया है । स्केला "लक्षण" मेरे लिए बिल्कुल भी लक्षण नहीं लगते हैं, क्योंकि उनके पास राज्य है, उनकी संरचना में रैखिककरण का उपयोग करें, और ऐसा प्रतीत होगा कि वे विधि संघर्षों को भी हल करते हैं - और ये सभी चीजें हैं जो पारंपरिक लक्षण नहीं हैं की है। वास्तव में, मैं कहूंगा कि स्कैल लक्षण लक्षण की तरह मिश्रण की तरह हैं। तुम क्या सोचते हो? PS: मैंने कभी स्काला में कोडिंग नहीं की है।
एडिनो

एक श्रोता के रूप में कार्य करने वाले इंटरफ़ेस में विधियों के लिए रिक्त डिफ़ॉल्ट कार्यान्वयन का उपयोग कैसे करें? श्रोता कार्यान्वयन केवल कुछ इंटरफ़ेस विधियों के लिए सुनने में रुचि रख सकता है, इसलिए विधियों को डिफ़ॉल्ट बनाकर, कार्यान्वयनकर्ता को केवल उन तरीकों को लागू करना होगा, जिन्हें सुनने की आवश्यकता है।
लाहिरू चंदिमा

1
@LahiruChandima की तरह MouseListener? यह एपीआई शैली समझ में आता है, यह "वैकल्पिक तरीकों" बाल्टी में फिट बैठता है। स्पष्ट रूप से वैकल्पिक-नेस दस्तावेज़ करने के लिए सुनिश्चित करें!
ब्रायन गोएट्ज

हाँ। बस के रूप में MouseListener। जवाब देने के लिए धन्यवाद।
लाहिरु चंदिमा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.