Grokking जावा संस्कृति - चीजें इतनी भारी क्यों हैं? इसके लिए क्या अनुकूलन है? [बन्द है]


288

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

जावा सिंटैक्स कोई समस्या नहीं है; यह सिर्फ एक और भाषा है। लेकिन सिंटैक्स के अलावा, जावा में एक संस्कृति है, विकास विधियों का एक सेट है, और प्रथाओं को "सही" माना जाता है। और अब मैं उस संस्कृति को "टटोलने" में पूरी तरह से विफल हो रहा हूं। इसलिए मैं सही दिशा में स्पष्टीकरण या संकेत की सराहना करूंगा।

एक स्टैक ओवरफ्लो प्रश्न में एक न्यूनतम पूर्ण उदाहरण उपलब्ध है जो मैंने शुरू किया था: https://stackoverflow.com/questions/43619566/returning-a-result-with-several-values-the-java-way/43620339

मेरे पास एक कार्य है - पार्स (एक स्ट्रिंग से) और तीन मानों के एक सेट को संभालना। पायथन में यह पास्कल या सी में 5-लाइनर रिकॉर्ड / स्ट्रक्चर में एक-लाइनर (ट्यूपल) है।

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

मैं समझता हूं कि एक विशाल विकास समुदाय संभवतः "गलत" नहीं है। तो यह मेरी समझ के साथ एक समस्या है।

पायथन अभ्यास पठनीयता के लिए अनुकूलन करता है (जो कि उस दर्शन में, स्थिरता की ओर जाता है) और उसके बाद, विकास की गति। सी अभ्यास संसाधन उपयोग के लिए अनुकूलन करते हैं। जावा प्रैक्टिस किसके लिए ऑप्टिमाइज़ करते हैं? मेरा सबसे अच्छा अनुमान स्केलेबिलिटी है (सब कुछ एक राज्य में लाखों-एलओसी परियोजना के लिए तैयार होना चाहिए), लेकिन यह बहुत कमजोर अनुमान है।


1
सवाल के तकनीकी पहलुओं का जवाब न दें लेकिन फिर भी संदर्भ में: softwareengineering.stackexchange.com/a/63145/13899
Newtopian



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

1
जावा के वास्तविक कारण मानक होने के कारण यह सही है। यह सही तरीके से बनाया गया था, पहली बार, गंभीर लोगों द्वारा जो दाढ़ी से पहले दाढ़ी फैशनेबल थे। यदि आप फ़ाइलों में हेरफेर करने के लिए शेल स्क्रिप्ट्स का उपयोग करने के लिए उपयोग किए जाते हैं, तो जावा असहिष्णु रूप से फूला हुआ लगता है। लेकिन अगर आप एक दोहरी निरर्थक सर्वर क्लस्टर बनाना चाहते हैं, जो प्रतिदिन 50M लोगों की सेवा करने में सक्षम है, जो कि क्लस्टर्ड रेडिस कैशिंग, 3 बिलिंग सिस्टम और 20M पाउंड ऑरेकल डेटाबेस क्लस्टर द्वारा समर्थित है। आप अजगर का उपयोग नहीं करने जा रहे हैं, भले ही वह एक्सेस कर रहा हो पायथन में डेटाबेस 25 लाइनों का कम कोड है।
रिचर्ड

जवाबों:


237

जावा भाषा

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

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

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


जावा संस्कृति

उद्यम जावा विकास का इतिहास काफी हद तक हमें उस संस्कृति के लिए प्रेरित करता है जिसे हम आज देखते हैं। 90 के दशक के अंत / 00 के दशक के प्रारंभ में, जावा सर्वर-साइड व्यावसायिक अनुप्रयोगों के लिए एक अत्यंत लोकप्रिय भाषा बन गई। फिर उन अनुप्रयोगों को बड़े पैमाने पर तदर्थ लिखा गया और कई जटिल चिंताओं को शामिल किया गया, जैसे कि HTTP एपीआई, डेटाबेस और एक्सएमएल फीड को संसाधित करना।

00 के दशक में यह स्पष्ट हो गया कि इनमें से कई अनुप्रयोगों में इन चिंताओं को प्रबंधित करने के लिए बहुत कुछ सामान्य और रूपरेखाएं थीं, जैसे कि हाइबरनेट ORM, Xerces XML पार्सर, JSPs और सर्वलेट एपीआई और EJB, लोकप्रिय हो गए। हालाँकि, जब इन रूपरेखाओं ने उस विशेष डोमेन में काम करने के प्रयास को कम कर दिया जिसे वे स्वचालित करने के लिए सेट करते हैं, तो उन्हें कॉन्फ़िगरेशन और समन्वय की आवश्यकता होती है। उस समय, जो भी कारण के लिए, यह सबसे जटिल उपयोग के मामले को पूरा करने के लिए चौखटे लिखने के लिए लोकप्रिय था और इसलिए इन पुस्तकालयों को स्थापित करने और एकीकृत करने के लिए जटिल था। और समय के साथ वे तेजी से जटिल होते गए क्योंकि वे सुविधाएँ जमा करते गए। जावा उद्यम विकास धीरे-धीरे तीसरे पक्ष के पुस्तकालयों को एक साथ प्लग करने और एल्गोरिदम लिखने के बारे में कम हो गया।

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

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


15
यह मजेदार है कि अन्य भाषाएं कुछ "जावा-इस्स" उठा रही हैं। PHP OO सुविधाएँ जावा से बहुत अधिक प्रेरित हैं, और आजकल जावास्क्रिप्ट को अक्सर इसकी भारी मात्रा में रूपरेखा के लिए आलोचना की जाती है और सभी निर्भरताओं को इकट्ठा करने और एक नया आवेदन शुरू करने के लिए कितना कठिन है।
मार्कस

14
@marcus हो सकता है क्योंकि कुछ लोगों ने आखिरकार "पहिया को सुदृढ़ नहीं करते" बात सीखी? निर्भरताएं पहिया को फिर से
मजबूत

9
"ट्रिक" अक्सर आर्कियन , "चतुर" , कोड-गोल्फ-ईश वन-लाइनर्स में अनुवाद करता है।
ट्यूलेंस कोर्डोवा

7
सुविचारित, सुविचारित उत्तर। ऐतिहासिक संदर्भ। अपेक्षाकृत अनपढ़। अच्छी तरह से किया।
शेजमिस्टर

10
@ TulainsCórdova मैं सहमत हूं कि हमें "प्लेग से बचना चाहिए ... प्लेग की तरह चतुर चालें" (डोनाल्ड नथ), लेकिन इसका मतलब यह नहीं है कि forजब एक लूप लिखना mapअधिक उचित (और पठनीय) होगा। एक खुशहाल माध्यम है।
बजे ब्रायन मैककचटन

73

मेरा मानना ​​है कि मेरे पास आपके द्वारा उठाए गए बिंदुओं में से एक का जवाब है जो दूसरों द्वारा नहीं उठाया गया है।

जावा कभी भी कोई धारणा नहीं बनाकर संकलन-समय प्रोग्रामर त्रुटियों का पता लगाने के लिए अनुकूलन करता है

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

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

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

आपके मामले में, इसका मतलब है कि संकलक के लिए यह गारंटी देने के लिए कि आप वास्तव में उन प्रकारों को वापस कर रहे हैं जो आपको लगता है कि आप लौट रहे हैं, आपको संकलक को वह जानकारी प्रदान करने की आवश्यकता है।

जावा में ऐसा करने के दो तरीके हैं:

  1. का प्रयोग करें Triplet<A, B, C>(वापसी प्रकार के रूप में जो वास्तव में होना चाहिए java.util, और मैं वास्तव में व्याख्या नहीं कर सकते कारण है कि यह नहीं है। विशेष रूप से के बाद से JDK8 परिचय Function, BiFunction, Consumer, BiConsumer, आदि ... यह सिर्फ इतना है कि लगता है Pairऔर Tripletकम से कम मतलब होगा। लेकिन मैं पीछे हटना )

  2. उस उद्देश्य के लिए अपना स्वयं का प्रकार बनाएँ, जहाँ प्रत्येक फ़ील्ड का नाम और ठीक से टाइप किया गया हो।

उन दोनों मामलों में, कंपाइलर गारंटी दे सकता है कि आपका फ़ंक्शन घोषित किए गए प्रकारों को वापस कर देता है, और कॉलर को पता चलता है कि प्रत्येक लौटे हुए फ़ील्ड का प्रकार क्या है और तदनुसार उनका उपयोग करता है।

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

टाइपस्क्रिप्ट (या फ्लो टाइप) में कुछ इस तरह से विचार करें जहां स्पष्ट टाइपिंग के बजाय टाइप इंफ़ेक्शन का उपयोग किया जाता है।

function parseDurationInMillis(csvLine){
    // here the developer intends to return a Number, 
    // but actually it's a String
    return csv.firstField();
}

// Compiler infers that parseDurationInMillis is String, so it does
// string concatenation and infers that plusTwoSeconds is String
// Developer actually intended Number
var plusTwoSeconds = 2000 + parseDurationInMillis(csvLine);

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


ध्यान दें कि उचित ऑब्जेक्ट ओरिएंटेड सिद्धांतों और डोमेन-संचालित मॉडलिंग के बाद, लिंक किए गए प्रश्न में अवधि पार्सिंग मामले को भी java.time.Durationऑब्जेक्ट के रूप में वापस किया जा सकता है , जो कि उपरोक्त दोनों मामलों में बहुत अधिक स्पष्ट होगा।


38
यह कहते हुए कि जावा कोड शुद्धता के लिए अनुकूलन करता है, एक वैध बिंदु हो सकता है, लेकिन यह मुझे लगता है (बहुत सारी भाषाएं, हाल ही में थोड़ी जावा) प्रोग्रामिंग, ऐसा लगता है कि भाषा या तो विफल हो जाती है या ऐसा करने में बेहद अक्षम है। दी, जावा पुराना है और बहुत सारा सामान वापस मौजूद नहीं था, लेकिन आधुनिक विकल्प हैं जो यकीनन बेहतर शुद्धता जाँच प्रदान करते हैं, जैसे हास्केल (और मैं कहता हूं? रस्ट या गो)। इस लक्ष्य के लिए जावा की सभी अस्वाभाविकता अनावश्यक है। - और इसके अलावा, यह नहीं है सब पर संस्कृति की व्याख्या है, लेकिन Solomonoff पता चला है कि संस्कृति बी एस वैसे भी है।
tomsmeding

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

39
@tomsmeding यह ध्यान देने योग्य है कि यह तर्क विशेष रूप से मूर्खतापूर्ण है क्योंकि हास्केल जावा की तुलना में लगभग 5 साल लंबा है। जावा में एक प्रकार की प्रणाली हो सकती है, लेकिन इसे जारी किए जाने पर कला शुद्धता सत्यापन की स्थिति भी नहीं थी।
एलेक्सिस किंग

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

19
@KonradRudolph हाँ, यह उत्तर पूरी तरह से निरर्थक है, हालांकि मुझे लगता है कि यह भावनात्मक रूप से आकर्षक है। मुझे यकीन नहीं है कि इसमें इतने वोट क्यों हैं। हास्केल (या शायद और भी अधिक, इदरीस) जावा की तुलना में शुद्धता के लिए कहीं अधिक अनुकूलन करता है, और इसमें एक हल्के वाक्यविन्यास के साथ ट्यूपल्स हैं। क्या अधिक है, एक डेटा प्रकार को परिभाषित करना एक-लाइनर है, और आपको जावा संस्करण प्राप्त होगा सब कुछ मिलता है। यह उत्तर खराब भाषा डिजाइन और अनावश्यक क्रियाशीलता का एक बहाना है, लेकिन यह अच्छा लगता है यदि आप जावा को पसंद करते हैं और अन्य भाषाओं से परिचित नहीं हैं।
एलेक्सिस किंग

50

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

  • दोनों के बीच विकास की लागत एक लंबे गुब्बारे वाले गुब्बारे में हवा की तरह होती है। आप गुब्बारे के एक हिस्से को और दूसरे हिस्से को सूंघ सकते हैं। पायथन ने शुरुआती भाग को निचोड़ दिया। जावा बाद के हिस्से को निचोड़ता है।
  • जावा में अभी भी कुछ विशेषताओं का अभाव है जो इस भार को दूर करेगा। जावा 8 ने इसमें बहुत बड़ी सेंध लगाई लेकिन संस्कृति ने परिवर्तनों को पूरी तरह से पचा नहीं लिया। जावा कुछ और चीजों का उपयोग कर सकता है जैसे कि yield

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

आपके द्वारा निर्दिष्ट विशिष्ट मामले में, कोई ट्यूपल्स नहीं हैं। इसका आसान उपाय यह है कि सार्वजनिक मूल्यों के साथ एक वर्ग बनाया जाए। जब जावा पहली बार बाहर आया, तो लोगों ने इसे नियमित रूप से किया। ऐसा करने के साथ पहली समस्या यह है कि यह एक रखरखाव सिरदर्द है। यदि आपको कुछ तर्क या धागा सुरक्षा जोड़ने की आवश्यकता है या बहुरूपता का उपयोग करना चाहते हैं, तो आपको उस 'टपल-एस्क' ऑब्जेक्ट के साथ बातचीत करने वाले प्रत्येक वर्ग को छूने की बहुत कम से कम आवश्यकता होगी। पायथन में इसके लिए समाधान जैसे कि __getattr__आदि हैं इसलिए यह इतना गंभीर नहीं है।

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

public class Blah 
{
  public static Blah blah(long number, boolean isInSeconds, boolean lessThanOneMillis)
  {
    return new Blah(number, isInSeconds, lessThanOneMillis);
  }

  private final long number;
  private final boolean isInSeconds;
  private final boolean lessThanOneMillis;

  public Blah(long number, boolean isInSeconds, boolean lessThanOneMillis)
  {
    this.number = number;
    this.isInSeconds = isInSeconds;
    this.lessThanOneMillis = lessThanOneMillis;
  }

  public long getNumber()
  {
    return number;
  }

  public boolean isInSeconds()
  {
    return isInSeconds;
  }

  public boolean isLessThanOneMillis()
  {
    return lessThanOneMillis;
  }
}

यह एक तरह का पैटर्न है जिसका मैं उपयोग करता हूं। यदि आप एक आईडीई का उपयोग नहीं कर रहे हैं, तो आपको शुरू करना चाहिए। यह आपके लिए गेटर्स उत्पन्न करेगा (और यदि आपको उनकी आवश्यकता है) तो यह इतना दर्दनाक नहीं है।

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

public class Blah 
{
  public static Blah fromSeconds(long number)
  {
    return new Blah(number * 1000_000);
  }

  public static Blah fromMills(long number)
  {
    return new Blah(number * 1000);
  }

  public static Blah fromNanos(long number)
  {
    return new Blah(number);
  }

  private final long nanos;

  private Blah(long nanos)
  {
    this.nanos = nanos;
  }

  public long getNanos()
  {
    return nanos;
  }

  public long getMillis()
  {
    return getNanos() / 1000; // or round, whatever your logic is
  }

  public long getSeconds()
  {
    return getMillis() / 1000; // or round, whatever your logic is
  }

  /* I don't really know what this is about but I hope you get the idea */
  public boolean isLessThanOneMillis()
  {
    return getMillis() < 1;
  }
}

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
maple_shaft

2
मेरा सुझाव है कि आप
स्कैला

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

यह उत्तर ओपी द्वारा उठाए गए अनुमानित मूल्य पहलू को संबोधित नहीं करता है।
एरिक

@ प्रश्न प्रश्न में "अनुमानित मूल्य" शब्द दिखाई नहीं देते हैं। यदि आप मुझे उस प्रश्न के विशिष्ट भाग की ओर संकेत कर सकते हैं, जिसे मैंने संबोधित नहीं किया है, तो मैं ऐसा करने का प्रयास कर सकता हूं।
जिमीजैम

41

इससे पहले कि आप जावा में बहुत अधिक पागल हो जाएं, कृपया मेरे उत्तर को अपनी अन्य पोस्ट में पढ़ें ।

आपकी शिकायतों में से एक को उत्तर के रूप में मानों के कुछ सेट को वापस करने के लिए एक वर्ग बनाने की आवश्यकता है। यह एक वैध चिंता है कि मुझे लगता है कि आपके प्रोग्रामिंग अंतर्ज्ञान ट्रैक पर सही हैं! हालाँकि, मुझे लगता है कि अन्य उत्तर उस आदिम जुनून विरोधी पैटर्न से चिपके हुए हैं जो आपने किए हैं। और जावा में कई प्राइमेट के साथ काम करने में उतनी ही आसानी नहीं है जितनी कि पायथन के पास है, जहाँ आप कई मानों को मूल रूप से वापस कर सकते हैं और उन्हें आसानी से कई वेरिएबल्स में असाइन कर सकते हैं।

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

क्या आपका कोड ऐसा है जो लगभग एक साथ अवधि (या त्रुटि के एक अंश के साथ अवधि) को सम्‍मिलित करता है, हालाँकि आप इसका पूर्ण रूप से प्रतिनिधित्व करते हैं) या इस पर कोई ऑब्जेक्ट-नेस है? मेरा प्रस्ताव है कि समरूप अवधि के योग के आस-पास की अच्छी डिज़ाइन एक साथ एक वर्ग के भीतर किसी भी उपभोग कोड के बाहर ऐसा करने का हुक्म देगी, जिसे स्वयं परखा जा सके। मुझे लगता है कि इस तरह के डोमेन ऑब्जेक्ट का उपयोग करने से आपके कोड में एक सकारात्मक तरंग प्रभाव होगा जो आपको एकल-जिम्मेदारी वर्गों की ओर (एक साथ कई जिम्मेदारियों के साथ) एकल-स्तरीय कार्य को पूरा करने के लिए लाइन-बाय-लाइन प्रक्रियात्मक चरणों से दूर चलाने में मदद करता है। जो विभिन्न चिंताओं के टकराव से मुक्त हैं।

उदाहरण के लिए, मान लें कि आप इस बारे में अधिक जानकारी प्राप्त करते हैं कि वास्तव में आपकी अवधि के लिए सटीक और पैमाने की आवश्यकता क्या है और सही ढंग से काम करने की तुलना के लिए, और आपको पता चलता है कि आपको "लगभग 32 मिलीसेकंड त्रुटि" (वर्ग के करीब) इंगित करने के लिए एक मध्यवर्ती ध्वज की आवश्यकता है 1000 की जड़, तो 1 और 1000 के बीच आधा लघुगणक। यदि आपने अपने आप को ऐसे कोड के लिए बाध्य किया है जो इसे दर्शाने के लिए आदिम का उपयोग करता है, तो आपको उस कोड में हर जगह ढूंढनी होगी जहां आपके पास है is_in_seconds,is_under_1msऔर इसे बदल देंis_in_seconds,is_about_32_ms,is_under_1ms। हर जगह सब कुछ बदलना होगा! एक वर्ग बनाना जिसकी ज़िम्मेदारी त्रुटि के मार्जिन को दर्ज करना है ताकि इसे कहीं और उपभोग किया जा सके, अपने उपभोक्ताओं को त्रुटि मामले के मार्जिन या कुछ भी कैसे वे गठबंधन करते हैं, के विवरण जानने से मुक्त करता है, और उन्हें सिर्फ त्रुटि के मार्जिन को निर्दिष्ट करने देता है जो प्रासंगिक है इस समय। (अर्थात, कोई भी खपत कोड, जिसकी त्रुटि का मार्जिन सही है, जब आप कक्षा में त्रुटि स्तर का एक नया मार्जिन जोड़ते हैं, तो परिवर्तन के लिए मजबूर किया जाता है, क्योंकि त्रुटि के सभी पुराने मार्जिन अभी भी मान्य हैं)।

बंद बयान

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

परिशिष्ट

मैं पूरी तरह से गलत तरीके से और गलत तरीके से जोड़ दूंगा कि सी # की स्वचालित संपत्तियों और असाइनमेंट में केवल गुणों को प्राप्त करने की क्षमता से कुछ हद तक गड़बड़ कोड को साफ करने में मदद मिलती है कि "जावा तरीके" की आवश्यकता होगी (स्पष्ट निजी बैकिंग फ़ील्ड और गेट्टर / सेटर फ़ंक्शन के साथ) :

// Warning: C# code!
public sealed class ApproximateDuration {
   public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
      LowMilliseconds = lowMilliseconds;
      HighMilliseconds = highMilliseconds;
   }
   public int LowMilliseconds { get; }
   public int HighMilliseconds { get; }
}

यहाँ ऊपर के एक जावा कार्यान्वयन है:

public final class ApproximateDuration {
  private final int lowMilliseconds;
  private final int highMilliseconds;

  public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
    this.lowMilliseconds = lowMilliseconds;
    this.highMilliseconds = highMilliseconds;
  }

  public int getLowMilliseconds() {
    return lowMilliseconds;
  }

  public int getHighMilliseconds() {
    return highMilliseconds;
  }
}

अब यह बहुत साफ है। अपरिवर्तनीयता के बहुत महत्वपूर्ण और जानबूझकर उपयोग पर ध्यान दें - यह इस विशेष प्रकार के मूल्य-असर वर्ग के लिए महत्वपूर्ण लगता है।

उस मामले के लिए, यह वर्ग भी एक होने के लिए एक सभ्य उम्मीदवार है struct, एक मूल्य प्रकार। कुछ परीक्षण बताएंगे कि क्या किसी संरचना पर स्विच करने से रन-टाइम प्रदर्शन लाभ होता है (यह हो सकता है)।


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

2
यदि आपको यह उत्तर पसंद है, तो डोमेन-प्रेरित डिज़ाइन पर पढ़ें। कोड में डोमेन अवधारणाओं का प्रतिनिधित्व करने के इस विषय पर बहुत कुछ कहना है।
नॉनटापिर

@neontapir हां, धन्यवाद! मुझे पता था कि इसके लिए एक नाम था! :-) हालाँकि मुझे कहना होगा कि मैं इसे पसंद करता हूँ जब एक डोमेन कॉन्सेप्ट ऑर्गनाइज़िंग बिट के एक प्रेरित बिट से (जैसे)! ।
सुसैन

@ सुसानव मैं सहमत हूँ। डोमेन अवधारणाओं को उजागर करने के लिए आदिम जुनून को दूर करने का एक शानदार तरीका हो सकता है!
नोनटापिर

मैंने चर्चा की उदाहरण के जावा संस्करण को जोड़ा। मैं C # में सभी मैजिक सिंथेटिकल शुगर पर नहीं हूं, इसलिए यदि कोई चीज गायब है, तो मुझे बताएं।
जिमीजैम

24

पायथन और जावा दोनों अपने डिजाइनरों के दर्शन के अनुसार स्थिरता के लिए अनुकूलित हैं, लेकिन उनके पास इस बारे में बहुत अलग विचार हैं कि इसे कैसे प्राप्त किया जाए।

पायथन एक बहु-प्रतिमान भाषा है जो कोड की स्पष्टता और सरलता (पढ़ने और लिखने में आसान) के लिए अनुकूलन करती है ।

जावा (पारंपरिक) एक एकल प्रतिमान वर्ग आधारित OO भाषा है जिसके लिए अनुकूलित करता है मुखरता और स्थिरता और भी अधिक वर्बोज़ कोड की कीमत पर -।

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

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

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


+1, लेकिन स्कैला जैसे वर्गों के साथ सांख्यिकीय रूप से टाइप की जाने वाली भाषाओं के साथ यह जाल कैसे होता है, जो फिर भी ट्यूपल्स को पेश करने की आवश्यकता नहीं पाई? मुझे लगता है कि कुछ मामलों में ट्यूपल्स केवल कक्षा के साथ भाषाओं के लिए भी समाधान हैं।
एंड्रेस एफ।

@AndresF: आप मेष से क्या मतलब है? स्काला जावा से अलग एक भाषा है और इसमें विभिन्न डिजाइन सिद्धांत और मुहावरे हैं।
जैक्सबीज

मेरा मतलब है कि यह आपके 5 वें पैराग्राफ के उत्तर में है, जो "लेकिन यह वास्तव में जावा संस्कृति [...] से मेल नहीं खाता है।" वास्तव में, मैं मानता हूं कि वर्बोसिटी जावा की संस्कृति का हिस्सा है, लेकिन ट्यूपल्स की कमी नहीं हो सकती है क्योंकि वे "पहले से ही स्पष्ट रूप से घोषित वर्गों का उपयोग करते हैं" - आखिरकार, स्काला में भी स्पष्ट कक्षाएं हैं (और अधिक संक्षिप्त मामला कक्षाओं का परिचय देता है ), लेकिन यह भी tuples की अनुमति देता है! अंत में, मुझे लगता है कि यह संभव है कि जावा ने न केवल ट्यूल को पेश किया था क्योंकि कक्षाएं समान (अधिक अव्यवस्था के साथ) प्राप्त कर सकती हैं, बल्कि इसलिए भी कि इसके सिंटैक्स को सी प्रोग्रामर से परिचित होना चाहिए, और सी के पास ट्यूपल्स नहीं थे।
एंड्रेस एफ।

@AndresF .: स्काला के पास काम करने के कई तरीकों के खिलाफ एक विरोध नहीं है, यह दोनों कार्यात्मक प्रतिमान और शास्त्रीय OO से सुविधाओं को जोड़ती है। यह उस तरह से पायथन दर्शन के करीब है।
जाकबीस

@AndresF .: हां जावा ने C / C ++ के सिंटैक्स के साथ शुरुआत की, लेकिन बहुत सरल किया। C # जावा की लगभग एक सटीक प्रतिलिपि के रूप में शुरू हुआ, लेकिन पिछले कुछ वर्षों में इसमें बहुत सारी विशेषताएं शामिल हैं, जिसमें टुपल्स भी शामिल हैं। तो यह वास्तव में भाषा डिजाइन दर्शन में एक अंतर है। (जावा के बाद के संस्करणों को लगता है कि कम हठधर्मी है। उच्च-क्रम फ़ंक्शन को शुरू में खारिज कर दिया गया था क्योंकि आप वही कर सकते थे जो कि कक्षाएं हैं, लेकिन अब उन्हें पेश किया गया है। इसलिए शायद हम दर्शन में बदलाव देख रहे हैं।)
जैक्सबीस

16

प्रथाओं की खोज मत करो; यह आमतौर पर एक बुरा विचार है, जैसा कि सर्वोत्तम प्रथाओं बीएडी, पैटर्न गुड में कहा गया है ? । मुझे पता है कि आप सर्वोत्तम प्रथाओं के लिए नहीं पूछ रहे हैं, लेकिन मुझे अभी भी लगता है कि आपको कुछ प्रासंगिक तत्व मिलेंगे।

आपकी समस्या के समाधान के लिए खोज करना एक अभ्यास से बेहतर है, और आपकी समस्या जावा फास्ट में तीन मान वापस करने के लिए कोई समस्या नहीं है:

  • अर्र हैं
  • आप एक लाइनर में एक सूची के रूप में एक सरणी वापस कर सकते हैं: Arrays.asList (...)
  • यदि आप कम बायलरप्लेट के साथ ऑब्जेक्ट को साइड में रखना चाहते हैं (और कोई लुम्बोक):

class MyTuple {
    public final long value_in_milliseconds;
    public final boolean is_in_seconds;
    public final boolean is_under_1ms;
    public MyTuple(long value_in_milliseconds,....){
        ...
    }
 }

यहां आपके पास एक अपरिवर्तनीय वस्तु है जिसमें केवल आपका डेटा है, और सार्वजनिक है ताकि गेटर्स की कोई आवश्यकता न हो। ध्यान दें कि यदि आप कुछ क्रमांकन उपकरण या एक ORM की तरह दृढ़ता परत का उपयोग करते हैं, तो वे सामान्यतः गेट्टर / सेटर का उपयोग करते हैं (और गेट्टर / सेटर के बजाय फ़ील्ड का उपयोग करने के लिए एक पैरामीटर स्वीकार कर सकते हैं)। और यही कारण है कि इन प्रथाओं का बहुत उपयोग किया जाता है। इसलिए यदि आप प्रथाओं के बारे में जानना चाहते हैं, तो यह समझना बेहतर है कि वे उनके बेहतर उपयोग के लिए यहां क्यों हैं।

अंत में: मैं गेटर्स का उपयोग करता हूं क्योंकि मैं बहुत सीरियलाइजेशन टूल्स का उपयोग करता हूं, लेकिन मैं उन्हें न तो लिखता हूं; मैं लुम्बोक का उपयोग करता हूं: मैं अपने आईडीई द्वारा प्रदान किए गए शॉर्टकट का उपयोग करता हूं।


9
आपके पास विभिन्न भाषाओं में आने वाले सामान्य मुहावरों को समझने में अभी भी मूल्य है, क्योंकि वे एक अधिक सुलभ डी वास्तविक मानक बन जाते हैं। वे मुहावरे किसी भी कारण से "सर्वोत्तम प्रथाओं" की श्रेणी में आते हैं।
बेरिन लोरिट्श

3
अरे, समस्या का एक समझदार समाधान। यह केवल [gs] etters के साथ एक पूर्ण विकसित इंजीनियर OOP समाधान के बजाय कुछ सार्वजनिक सदस्यों के साथ एक वर्ग (/ संरचना) लिखने के लिए काफी उचित लगता है।
tomsmeding

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

2
@MikhailRamendik यह YAGNI और OOP के बीच का व्यापार है। रूढ़िवादी OOP का कहना है कि हर एक वस्तु को बदली जानी चाहिए; केवल एक चीज जो मायने रखती है वह है वस्तु का सार्वजनिक इंटरफ़ेस। यह आपको कोड लिखने की अनुमति देता है जो कंक्रीट ऑब्जेक्ट्स पर कम ध्यान केंद्रित करता है, और इंटरफेस पर अधिक; और चूँकि फ़ील्ड एक इंटरफ़ेस का हिस्सा नहीं हो सकते हैं, आप उन्हें कभी उजागर नहीं करते हैं। यह कर सकते हैं कोड बहुत आसान लंबे समय में बनाए रखने के लिए करते हैं। अतिरिक्त, यह आपको अमान्य राज्यों को रोकने की अनुमति देता है। आपके मूल नमूने में, ऐसी वस्तु होना संभव है जो "<ms" और "s" दोनों हो, जो परस्पर अनन्य हैं। यह बुरी बात है।
लुआं

2
@PeterMortensen यह एक जावा पुस्तकालय है जो काफी असंबंधित चीजों को करता है। हालांकि यह बहुत अच्छा है। यहाँ विशेषताएं हैं
माइकल

11

जावा मुहावरों के बारे में सामान्य तौर पर:

जावा के हर चीज के लिए क्‍यों क्‍यों विभिन्‍न कारण हैं। जहाँ तक मेरा ज्ञान है, इसका मुख्य कारण है:

जावा को शुरुआती लोगों के लिए सीखना आसान होना चाहिए। अधिक स्पष्ट चीजें हैं, महत्वपूर्ण विवरणों को याद करना कठिन है। कम जादू ऐसा होता है जो शुरुआती लोगों के लिए मुश्किल होता है।


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

आप लोम्बोक जैसे उपकरणों के साथ बॉयलरप्लेट को कम कर सकते हैं:

@Value
class MyTuple {
    long value_in_milliseconds;
    boolean is_in_seconds;
    boolean is_under_1ms;
}

5
Google की AutoValue परियोजना भी है: github.com/google/auto/blob/master/value/userguide/index.md
इवान

यह भी है कि जावा कार्यक्रमों को अपेक्षाकृत आसानी से बनाए रखा
थोरबजोरन रावन एंडरसन 10

7

जावा संस्कृति के बारे में बहुत सी बातें कही जा सकती हैं, लेकिन मुझे लगता है कि जिस स्थिति में आप अभी सामना कर रहे हैं, उसके कुछ महत्वपूर्ण पहलू हैं:

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

खेतों के साथ "संरचना" कक्षाएं

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

   class ParseResult0 {
      public final long millis;
      public final boolean isSeconds;
      public final boolean isLessThanOneMilli;

      public ParseResult0(long millis, boolean isSeconds, boolean isLessThanOneMilli) {
         this.millis = millis;
         this.isSeconds = isSeconds;
         this.isLessThanOneMilli = isLessThanOneMilli;
      }
   }

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

एक और नुकसान यह है कि एक वर्ग आधारित दृष्टिकोण के साथ, आप क्षेत्रों को उजागर कर रहे हैं और उन सभी क्षेत्रों में मान होना चाहिए । जैसे, isSeconds और millis में हमेशा कुछ value होती है, भले ही isLessThanOneMilli सच हो। जब isLessThanOneMilli सच है तो मिलिस फ़ील्ड के मूल्य की व्याख्या क्या होनी चाहिए?

इंटरफेसेस के रूप में "स्ट्रक्चर्स"

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

   interface ParseResult {
      long getMillis();

      boolean isSeconds();

      boolean isLessThanOneMilli();

      static ParseResult from(long millis, boolean isSeconds, boolean isLessThanOneMill) {
         return new ParseResult() {
            @Override
            public boolean isSeconds() {
               return isSeconds;
            }

            @Override
            public boolean isLessThanOneMilli() {
               return isLessThanOneMill;
            }

            @Override
            public long getMillis() {
               return millis;
            }
         };
      }
   }

यह अभी भी बहुत सारे बॉयलरप्लेट है, मैं बिल्कुल सहमत हूं, लेकिन इसके कुछ फायदे भी हैं, और मुझे लगता है कि उन लोगों को आपके कुछ मुख्य सवालों का जवाब मिलना शुरू हो जाता है।

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

return (true, 500, false)

जब आपका मतलब था:

return (500, true, false)

इस तरह के जावा इंटरफेस के साथ, आप संकलन नहीं कर सकते:

return ParseResult.from(true, 500, false);

बिल्कुल भी। आप को करना पड़ेगा:

return ParseResult.from(500, true, false);

यह सामान्य रूप से सांख्यिकीय रूप से टाइप की गई भाषाओं का लाभ है।

यह दृष्टिकोण आपको उन मूल्यों को प्रतिबंधित करने की क्षमता भी प्रदान करना शुरू कर देता है जिन्हें आप प्राप्त कर सकते हैं। उदाहरण के लिए, जब getMillis () को कॉल किया जाता है, तो आप जांच सकते हैं कि क्या isLessThanOneMilli () सही है, और यदि यह है, तो एक IllegalStateException (उदाहरण के लिए) को फेंक दें, क्योंकि उस मामले में मिली का कोई सार्थक मूल्य नहीं है।

यह मुश्किल से गलत बात कर रही है

ऊपर दिए गए इंटरफ़ेस उदाहरण में, आपके पास अभी भी समस्या है कि आप गलती से isSeconds और isLessThanOneMilli तर्कों को स्वैप कर सकते हैं, हालांकि, क्योंकि उनके पास एक ही प्रकार है।

व्यवहार में, आप वास्तव में TimeUnit और अवधि का उपयोग करना चाहते हैं, ताकि आपके पास एक परिणाम हो जैसे:

   interface Duration {
      TimeUnit getTimeUnit();

      long getDuration();

      static Duration from(TimeUnit unit, long duration) {
         return new Duration() {
            @Override
            public TimeUnit getTimeUnit() {
               return unit;
            }

            @Override
            public long getDuration() {
               return duration;
            }
         };
      }
   }

   interface ParseResult2 {

      boolean isLessThanOneMilli();

      Duration getDuration();

      static ParseResult2 from(TimeUnit unit, long duration) {
         Duration d = Duration.from(unit, duration);
         return new ParseResult2() {
            @Override
            public boolean isLessThanOneMilli() {
               return false;
            }

            @Override
            public Duration getDuration() {
               return d;
            }
         };
      }

      static ParseResult2 lessThanOneMilli() {
         return new ParseResult2() {
            @Override
            public boolean isLessThanOneMilli() {
               return true;
            }

            @Override
            public Duration getDuration() {
               throw new IllegalStateException();
            }
         };
      }
   }

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

  ParseResult2 x = ParseResult2.from(TimeUnit.MILLISECONDS, 32);
  ParseResult2 y = ParseResult2.lessThanOneMilli();

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

एक अन्य जवाब में उल्लेख किया गया है कि जावा के उद्यम-प्रकार की प्रकृति का अर्थ है कि आप उस समय के लिए अन्य पुस्तकालयों की रचना कर रहे हैं, जो पहले से मौजूद हैं, या अन्य लोगों के लिए पुस्तकालयों का उपयोग करने के लिए लिख रहे हैं। आपके सार्वजनिक एपीआई को परिणाम टाइप करने के लिए प्रलेखन से परामर्श करने के लिए बहुत समय की आवश्यकता नहीं होनी चाहिए यदि इसे टाला जा सकता है।

आप केवल एक बार इन संरचनाओं को लिखते हैं , लेकिन आप उन्हें कई बार बनाते हैं, इसलिए आप अभी भी चाहते हैं कि संक्षिप्त रचना (जो आपको मिलती है)। स्टैटिक टाइपिंग सुनिश्चित करता है कि जो डेटा आप उनसे प्राप्त कर रहे हैं, वह वही है जो आप अपेक्षा करते हैं।

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


मैंने अंत में TimeUnit के बजाय अपने स्वयं के एनम का उपयोग किया है, क्योंकि मैंने वास्तविक समय इकाइयों के साथ ही UNDER1MS को जोड़ा है। इसलिए अब मेरे पास दो फील्ड हैं, तीन नहीं हैं। (सिद्धांत रूप में, मैं TimeUnit.NANOSECONDS का दुरुपयोग कर सकता था, लेकिन यह बहुत भ्रमित करने वाला होगा।)
मिखाइल रामेंदिक

मैंने एक गेटर नहीं बनाया, लेकिन अब मैं यह देखता हूं कि कैसे एक गॉटर मुझे एक अपवाद को फेंकने की अनुमति देगा, अगर, originalTimeUnit=DurationTimeUnit.UNDER1MSकॉल करने वाले ने मिलीसेकंड मान को पढ़ने की कोशिश की।
मिखाइल रामेंदिक

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

1
@Veedrac मुझे यकीन नहीं है कि आपका क्या मतलब है। मेरे मुद्दा यह है कि यह वरबोस रूप में दर्शा इस तरह (भले ही अधिक समय लगता है), पुस्तकालय कोड लिखने के बाद से वहाँ अधिक समय बिताया हो जाएगा ठीक है था का उपयोग कर से कोड लिख यह।
जोशुआ टेलर

1
@Veedrac हाँ, यह सच है। लेकिन मैं बनाए रखना चाहते है कि है कोड है कि सार्थक दोबारा इस्तेमाल किया जाएगा, और कोड के बीच एक अंतर है कि नहीं होगा। उदाहरण के लिए, जावा पैकेज में, कुछ कक्षाएं सार्वजनिक हैं, और अन्य स्थानों से उपयोग की जाती हैं। उन एपीआई को अच्छी तरह से सोचा जाना चाहिए। आंतरिक रूप से, ऐसी कक्षाएं हैं जिन्हें केवल एक-दूसरे से बात करने की आवश्यकता हो सकती है। वे आंतरिक कपलिंग वे स्थान हैं जहां त्वरित और गंदी संरचनाएं (उदाहरण के लिए, एक वस्तु [] जिसमें तीन तत्व होने की उम्मीद है) ठीक हो सकती हैं। सार्वजनिक एपीआई के लिए, कुछ अधिक सार्थक और स्पष्ट रूप से आमतौर पर पसंद किया जाना चाहिए।
जोशुआ टेलर

7

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

स्वीकृत उत्तर एक सही व्यापारिक समाधान प्रदान करता है। कोई त्वरित अस्थायी वर्कअराउंड जिसे आपको पहले फेंकना होगा और सही ढंग से लागू करना होगा पहली बार आपको लौटे मूल्य के साथ कुछ भी व्यावहारिक करने की आवश्यकता होगी, लेकिन एक POJO वर्ग जो पुस्तकालयों के एक बड़े सेट के साथ कंपैटिबल है, जिसमें दृढ़ता, क्रमबद्धता / निरंकुशता शामिल है, इंस्ट्रूमेंटेशन और कुछ भी संभव है।

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

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


2
"कोई भी" तथ्यात्मक रूप से गलत नहीं है - ऐसे उपकरणों का भार है जो कम वाचालता के लिए अनुकूलन करते हैं, नियमित अभिव्यक्ति एक चरम उदाहरण है। लेकिन आप "मुख्य धारा जावा दुनिया में कोई नहीं" का मतलब हो सकता है, और उस जवाब को पढ़ने में बहुत समझ में आता है, धन्यवाद। वर्बोसिटी के साथ मेरी अपनी चिंता लेखन कोड खर्च करने का समय नहीं है बल्कि इसे पढ़ने में लगने वाला समय है; IDE पढ़ने का समय नहीं बचाएगा; लेकिन ऐसा लगता है कि विचार यह है कि 99% एक बार केवल इंटरफ़ेस परिभाषा पढ़ता है इसलिए यह संक्षिप्त होना चाहिए?
मिखाइल रामेंदिक

5

तीन अलग-अलग कारक हैं जो आपके द्वारा देखे जाने में योगदान करते हैं।

टुपल्स बनाम नामित क्षेत्र

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

भाषा वाक्य रचना

क्या वर्ग को घोषित करना आसान हो सकता है? मैं खेतों को सार्वजनिक करने या मानचित्र का उपयोग करने के बारे में बात नहीं कर रहा हूं, लेकिन स्काला के केस क्लासेस जैसे कुछ, जो आपके द्वारा वर्णित सेटअप के सभी लाभ प्रदान करते हैं लेकिन बहुत अधिक संक्षिप्त हैं:

case class Foo(duration: Int, unit: String, tooShort: Boolean)

हम ऐसा कर सकते थे - लेकिन एक लागत है: वाक्यविन्यास अधिक जटिल हो जाता है। बेशक यह कुछ मामलों के लिए, या यहां तक ​​कि अधिकांश मामलों के लिए, या यहां तक ​​कि अगले 5 वर्षों के लिए अधिकांश मामलों के लिए भी हो सकता है - लेकिन इसे न्याय करने की आवश्यकता है। वैसे, यह उन भाषाओं के साथ है जो आप खुद को संशोधित कर सकते हैं (यानी लिस्प) - और ध्यान दें कि सिंटैक्स की सादगी के कारण यह कैसे संभव हो जाता है। यहां तक ​​कि अगर आप वास्तव में भाषा को संशोधित नहीं करते हैं, तो एक सरल वाक्यविन्यास अधिक शक्तिशाली उपकरण सक्षम करता है; उदाहरण के लिए बहुत बार मुझे जावा के लिए उपलब्ध कुछ रीफैक्टरिंग विकल्प याद आते हैं, लेकिन स्काला के लिए नहीं।

भाषा दर्शन

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

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

अवधि इकाइयों से अलग क्यों है? बहुत सारे समय पुस्तकालय हैं जो आपको एक अवधि की घोषणा करते हैं - अवधि (5, सेकंड) (वाक्यविन्यास अलग-अलग) जैसे कुछ, जो तब आपको कहीं अधिक मजबूत तरीके से जो कुछ भी करना चाहते हैं वह करने देगा। हो सकता है कि आप इसे बदलना चाहते हों - अगर परिणाम [1] (या [2]?) एक 'घंटे' है और 3600 से गुणा क्यों किया जाए? और तीसरे तर्क के लिए - इसका उद्देश्य क्या है? मुझे लगता है कि कुछ बिंदु पर आपको "1ms से कम" या वास्तविक समय प्रिंट करना होगा - यह कुछ तर्क है जो स्वाभाविक रूप से समय डेटा के साथ है। यानी आपके पास इस तरह एक वर्ग होना चाहिए:

class TimeResult {
    public TimeResult(duration, unit, tooShort)
    public String getResult() {
        if tooShort:
           return "too short"
        else:
           return format(duration)
}

}

या जो कुछ भी आप वास्तव में डेटा के साथ करना चाहते हैं, इसलिए तर्क को एन्क्रिप्ट करना।

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

लेकिन जावा में कक्षाएं "भारी संरचनाएं" पर मेरा दृष्टिकोण यह है कि आप उन्हें डेटा कंटेनर के रूप में उपयोग करने के लिए नहीं हैं, बल्कि तर्क के स्व-निहित कोशिकाओं के रूप में उपयोग करते हैं।


क्या मैं चाहता हूँ कर अवधियों वाली वास्तव में उनमें से एक योग बना रही है और फिर एक और की तुलना के बारे में है। कोई आउटपुट शामिल नहीं है। तुलना को ध्यान में रखने की आवश्यकता है, इसलिए मुझे तुलना के समय मूल समय इकाइयों को जानना होगा।
मिखाइल रामेंदिक

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

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

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

@MikhailRamendik बायलरप्लेटी तरीके के बारे में अच्छी बात यह है कि एक बार आपके पास एक वर्ग है, तो आप इसे व्यवहार जोड़ सकते हैं। और / या इसे अपरिवर्तनीय बना दिया जैसा आपने किया था (यह ज्यादातर समय एक अच्छा विचार है; आप हमेशा एक नई वस्तु को राशि के रूप में वापस कर सकते हैं)। अंत में, आपका "अतिसुंदर" वर्ग आपके लिए आवश्यक सभी व्यवहार को ध्वस्त कर सकता है और फिर गेटर्स के लिए लागत नगण्य हो जाती है। इसके अलावा, आपको उनकी आवश्यकता हो सकती है या नहीं। उपयोग करने पर विचार lombok या autovalue
माॅर्टिनस

5

मेरी समझ में, मुख्य कारण हैं

  1. इंटरफेस दूर कक्षाओं को सार करने के लिए मूल जावा तरीका है।
  2. जावा केवल एक विधि से एक एकल मान लौटा सकता है - एक वस्तु या एक सरणी या एक देशी मूल्य (इंट / लंबे / डबल / फ्लोट / बूलियन)।
  3. इंटरफ़ेस में फ़ील्ड नहीं हो सकते, केवल विधियाँ हैं। यदि आप किसी क्षेत्र तक पहुंचना चाहते हैं, तो आपको एक विधि से गुजरना होगा - इसलिए गेटर्स और सेटरर्स।
  4. यदि कोई विधि इंटरफ़ेस लौटाती है, तो आपके पास वास्तव में वापस आने के लिए एक कार्यान्वयन वर्ग होना चाहिए।

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


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

और मैं "टुपल्स जावा में अच्छी तरह से काम नहीं करता है" से सहमत हूँ -व्यू। यदि आप जेनेरिक का उपयोग करते हैं तो यह बहुत जल्दी खत्म हो जाएगा।
थोरबजोरन रावन एंडरसन

@ ThorbjørnRavnAndersen वे स्काला में बहुत अच्छी तरह से काम करते हैं, जेनेरिक और टुपल्स के साथ एक सांख्यिकीय रूप से टाइप की गई भाषा । तो शायद यह जावा की गलती है?
एंड्रेस एफ।

@AndresF। कृपया "यदि आप जेनरिक का उपयोग करते हैं" पर ध्यान दें। जिस तरह से जावा यह करता है वह खुद को जटिल निर्माणों के लिए उधार नहीं देता है जैसे उदाहरण के लिए हास्केल। मैं तुलना करने के लिए स्काला को अच्छी तरह से नहीं जानता, लेकिन क्या यह सच है कि स्काला कई रिटर्न मूल्यों के लिए अनुमति देता है? यह काफी मदद कर सकता है।
थोरबजोरन रेव एंडरसन

@ ThorbjørnRavnAndersen Scala फ़ंक्शंस में एक ही रिटर्न वैल्यू होती है जो टूपल टाइप की हो सकती है (जैसे def f(...): (Int, Int)कि एक फंक्शन fजो वैल्यू देता है जो पूर्णांकों का ट्यूपल होता है)। मुझे यकीन नहीं है कि जावा में जेनेरिक समस्या इसके साथ हैं; उदाहरण के लिए, हास्केल भी प्रकार का क्षरण करता है। मुझे नहीं लगता कि जावा को टुपल्स नहीं होने का एक तकनीकी कारण है।
एंड्रेस एफ।

3

मैं जैक्सबी के जवाब से सहमत हूं

जावा (पारंपरिक रूप से) एक एकल-प्रतिमान वर्ग-आधारित OO भाषा है जो खोजकर्ता और संगति के लिए अनुकूलन करती है

लेकिन इसके लिए अनुकूलन करने के लिए खोजकर्ता और निरंतरता अंतिम लक्ष्य नहीं हैं। जब आप कहते हैं कि 'पठनीयता के लिए अजगर को अनुकूलित किया गया है', तो आप तुरंत उल्लेख करते हैं कि अंतिम लक्ष्य 'रखरखाव' और 'विकास की गति' है।

जब आप खोजकर्ता और निरंतरता, जावा तरीके से करते हैं तो आप क्या हासिल करते हैं? मेरा लेना यह है कि यह एक ऐसी भाषा के रूप में विकसित हुई है जो किसी भी सॉफ़्टवेयर समस्या को हल करने के लिए पूर्वानुमान, सुसंगत, समान तरीके प्रदान करने का दावा करती है।

दूसरे शब्दों में, जावा संस्कृति प्रबंधकों को यह विश्वास दिलाने के लिए अनुकूलित है कि वे सॉफ्टवेयर विकास को समझते हैं।

या, जैसा कि एक बुद्धिमान व्यक्ति ने बहुत समय पहले किया था ,

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


3

(यह उत्तर विशेष रूप से जावा के लिए स्पष्टीकरण नहीं है, बल्कि इसके बजाय "क्या भारी [प्रथाओं] के लिए अनुकूलन कर सकता है?") के सामान्य प्रश्न को संबोधित करता है।

इन दो सिद्धांतों पर विचार करें:

  1. जब आपका कार्यक्रम सही काम करता है तो यह अच्छा है। हमें उन कार्यक्रमों को लिखना आसान बनाना चाहिए जो सही काम करते हैं।
  2. जब आपका प्रोग्राम गलत काम करता है तो यह बुरा है। हमें उन कार्यक्रमों को लिखना कठिन बनाना चाहिए जो गलत काम करते हैं।

इन लक्ष्यों में से एक को अनुकूलित करने की कोशिश करना कभी-कभी दूसरे के रास्ते में आ सकता है (यानी गलत काम करना कठिन हो सकता है, सही काम करना मुश्किल हो सकता है या इसके विपरीत)।

किसी विशेष मामले में कौन से ट्रेडऑफ किए जाते हैं यह आवेदन, प्रोग्रामर या टीम के निर्णय पर निर्भर करता है, और संस्कृति (संगठन या भाषा समुदाय का)।

उदाहरण के लिए, यदि आपके प्रोग्राम में बग या कुछ घंटों के आउटेज से जान माल की हानि हो सकती है (चिकित्सा प्रणाली, वैमानिकी) या यहां तक ​​कि केवल पैसे (जैसे Google के विज्ञापन सिस्टम में लाखों डॉलर), तो आप अलग-अलग ट्रेडऑफ़ करेंगे (नहीं सिर्फ आपकी भाषा में, बल्कि इंजीनियरिंग संस्कृति के अन्य पहलुओं में भी) एक से एक पटकथा के लिए: यह संभवतः "भारी" पक्ष की ओर झुकाव है।

अन्य उदाहरण जो आपके सिस्टम को अधिक "भारी" बनाते हैं:

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

ये केवल कुछ उदाहरण हैं, आपको उन मामलों का अंदाजा देने के लिए, जहाँ चीजें "भारी" बनती हैं (और यह कठिन है कि आप केवल कुछ कोड जल्दी से लिखें) जानबूझकर जानबूझकर हो सकते हैं। (कोई यह भी तर्क दे सकता है कि यदि कोड लिखने के लिए बहुत अधिक प्रयास की आवश्यकता है, तो यह आपको कोड लिखने से पहले अधिक सावधानी से सोचने के लिए प्रेरित कर सकता है। बेशक तर्क की यह पंक्ति जल्दी हास्यास्पद हो जाती है।)

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


नोट : उपरोक्त सभी बस के बारे में है जब चीजें "भारी" हो जाती हैं। मैं पूरी तरह से यह दावा नहीं करता कि जावा या पायथन (या तो स्वयं भाषाएं, या उनकी संस्कृतियाँ) किसी विशेष मामले के लिए इष्टतम व्यापार बनाती हैं; तुम्हारे बारे में सोचना है। ऐसे ट्रेडऑफ़ पर दो संबंधित लिंक:


1
कोड पढ़ने के बारे में क्या ? वहां एक और ट्रेडऑफ है। विचित्र असंगतियों और विपुल अनुष्ठानों द्वारा भारित कोड को पढ़ना मुश्किल है; अपने आईडीई में बॉयलरप्लेट और अनावश्यक पाठ (और श्रेणी पदानुक्रम!) के साथ, यह देखना कठिन हो जाता है कि कोड वास्तव में क्या कर रहा है। मैं इस तर्क को देख सकता हूं कि कोड को लिखना आसान नहीं होना चाहिए (यकीन है कि अगर मैं इससे सहमत हूं, लेकिन इसकी कुछ योग्यता है), लेकिन यह निश्चित रूप से पढ़ना आसान होना चाहिए । स्पष्ट रूप से जटिल कोड को जावा के साथ बनाया जा सकता है और बनाया गया है - अन्यथा यह दावा करना मूर्खता होगी - लेकिन क्या यह इसकी वाचालता के लिए धन्यवाद था , या इसके बावजूद ?
एंड्रेस एफ।

@AndresF। मैंने इसका उत्तर स्पष्ट करने के लिए संपादित किया कि यह विशेष रूप से जावा के बारे में नहीं है (जिनमें से मैं बहुत बड़ा प्रशंसक नहीं हूं)। लेकिन हाँ, कोड पढ़ते समय ट्रेडऑफ़ करें: एक छोर पर आप "कोड वास्तव में क्या कर रहे हैं" को आसानी से पढ़ सकते हैं। दूसरे छोर पर, आप आसानी से प्रश्नों के उत्तर देख सकते हैं जैसे: यह कोड अन्य कोड से कैसे संबंधित है? यह कोड सबसे बुरा क्या कर सकता है: इसका प्रभाव दूसरे राज्य पर क्या हो सकता है, इसके दुष्प्रभाव क्या हैं? यह कोड किन बाहरी कारकों पर निर्भर करता है? (निश्चित रूप से आदर्श रूप से हम दोनों प्रश्नों के त्वरित उत्तर चाहते हैं।)
श्रीवत्सआर

2

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

अनुशंसा को प्रभावित करने वाला एक हिस्सा है जिसे पायथन और जावा में पठनीय और बनाए रखने योग्य माना जाता है।

  • पायथन में, टपल भाषा की एक विशेषता है।
  • Java और C # दोनों में, tuple एक पुस्तकालय सुविधा है (या होगा) ।

मैं केवल C # का उल्लेख करता हूं, क्योंकि मानक पुस्तकालय में टपल <A, B, C, .. n> वर्गों का एक सेट है, और यह एक आदर्श उदाहरण है कि यदि भाषा सीधे उनका समर्थन नहीं करती है, तो यह कितना अच्छा है। लगभग हर उदाहरण में, आपका कोड अधिक पठनीय और रखरखाव योग्य हो जाता है यदि आपके पास समस्या को संभालने के लिए अच्छी तरह से चुनी हुई कक्षाएं हैं। आपके लिंक किए गए स्टैक ओवरफ्लो प्रश्न में विशिष्ट उदाहरण में, अन्य मान आसानी से रिटर्न ऑब्जेक्ट पर गणना प्राप्तकर्ताओं के रूप में व्यक्त किए जाएंगे।

एक दिलचस्प समाधान जो सी # प्लेटफॉर्म ने किया था जो एक खुश मध्य मैदान प्रदान करता है वह है अनाम वस्तुओं ( सी # 3.0 में जारी ) का विचार जो इस खुजली को काफी अच्छी तरह से खरोंचता है। दुर्भाग्य से, जावा में अभी तक एक समकक्ष नहीं है।

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


4
सी # के नवीनतम संस्करण में नए ट्यूपल्स पुस्तकालय कक्षाओं के बजाय प्रथम श्रेणी के नागरिक हैं। वहाँ पहुँचने के लिए भी कई संस्करण लगे।
इगोर सोलोय्डेनको

अंतिम 3 पैराग्राफ को संक्षेप में कहा जा सकता है "भाषा एक्स में वह विशेषता है जो आप चाहते हैं कि जावा नहीं करता है", और मैं यह देखने में विफल रहता हूं कि वे उत्तर में क्या जोड़ते हैं। पायथन में जावा विषय पर C # का उल्लेख क्यों? नहीं, मैं अभी बात नहीं देख रहा हूँ। एक 20k + प्रतिनिधि आदमी से थोड़ा अजीब।
ओलिवियर ग्रेगोइरे

1
जैसा कि मैंने कहा, "मैं केवल C # का उल्लेख करता हूं क्योंकि Tuples एक पुस्तकालय सुविधा है" जो कि मुख्य पुस्तकालय में Tuples होने पर जावा में कैसे काम करेगा, इसके समान है। यह उपयोग करने के लिए बहुत ही सुंदर है, और बेहतर उत्तर लगभग हमेशा समर्पित वर्ग के लिए है। अनाम वस्तुएं टुपल्स के लिए डिज़ाइन किए गए समान खांचे को खरोंचती हैं, हालांकि। कुछ बेहतर करने के लिए भाषा के समर्थन के बिना, आपको अनिवार्य रूप से उस चीज के साथ काम करना होगा जो सबसे अधिक रखरखाव योग्य है।
बेरिन लोरिट्श

@IgorSoloydenko, शायद जावा 9 के लिए आशा है? यह उन विशेषताओं में से एक है जो लंबोदर के लिए अगला कदम है।
बेरिन लोरिट्श

1
@IgorSoloydenko मुझे यकीन नहीं है कि यह काफी हद तक सही है (प्रथम श्रेणी के नागरिक) - वे लाइब्रेरी से कक्षाओं के उदाहरणों को बनाने और अनचेक करने के लिए वाक्यविन्यास एक्सटेंशन हैं, बल्कि सीएलआर में क्लास, स्ट्रक्चर, एनम डू के रूप में प्रथम श्रेणी का समर्थन करते हैं।
पीट किरखम

0

मुझे लगता है कि इस मामले में एक वर्ग का उपयोग करने के बारे में एक मुख्य बात यह है कि जो एक साथ जाता है वह एक साथ रहना चाहिए।

मैंने इस पद्धति के बारे में अन्य तरीकों से चर्चा की है: बीएमआई की गणना करने वाली एक सरल विधि पर विचार करें:

CalculateBMI(weight,height)
{
  System.out.println("BMI: " + (( weight / height ) x 703));
}

इस मामले में मैं इस शैली के खिलाफ तर्क दूंगा क्योंकि वजन और ऊंचाई संबंधित हैं। विधि "संचार" वे दो अलग-अलग मान हैं जब वे नहीं होते हैं। आप एक व्यक्ति के वजन और दूसरे की ऊंचाई के साथ बीएमआई की गणना कब करेंगे? इसका कोई मतलब नहीं होगा।

CalculateBMI(Person)
{
  System.out.println("BMI: " + (( Person.weight / Person.height ) x 703));
}

बहुत अधिक समझ में आता है क्योंकि अब आप स्पष्ट रूप से संवाद करते हैं कि ऊंचाई और वजन एक ही स्रोत से आते हैं।

वही कई मूल्यों को लौटाने के लिए जाता है। यदि वे स्पष्ट रूप से जुड़े हुए हैं तो एक साफ छोटे पैकेज को लौटाएं और एक वस्तु का उपयोग करें, यदि वे कई मान वापस नहीं करते हैं।


4
ठीक है, लेकिन मान लीजिए कि आपके पास एक ग्राफ दिखाने के लिए एक (काल्पनिक) कार्य है: बीएमआई कुछ विशेष निश्चित ऊंचाई के लिए वजन पर कैसे निर्भर करता है। फिर, आप प्रत्येक डेटा बिंदु के लिए एक व्यक्ति बनाए बिना ऐसा नहीं कर सकते। और, इसे चरम पर ले जाकर, आप वैध जन्म तिथि और पासपोर्ट संख्या के बिना व्यक्ति वर्ग का उदाहरण नहीं बना सकते। अब क्या? मैंने btw को कम नहीं किया है, कुछ वर्ग में एक साथ गुणों को बांधने के वैध कारण हैं
आर्टेम

1
@ आर्टेम वह अगला कदम है जहां इंटरफेस खेलने में आता है। तो एक व्यक्ति का वजन इंटरफ़ेस कुछ ऐसा हो सकता है। आप उस उदाहरण को पकड़ने में सफल हो रहे हैं, जो मैंने इस बात के लिए दिया था कि जो एक साथ चलता है वह एक साथ होना चाहिए।
पीटर बी

0

स्पष्ट रूप से, संस्कृति यह है कि जावा प्रोग्रामर मूल रूप से उन विश्वविद्यालयों से बाहर निकलते हैं जहां ऑब्जेक्ट ओरिएंटेड सिद्धांतों और टिकाऊ सॉफ्टवेयर डिजाइन सिद्धांतों को पढ़ाया जाता था।

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

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

लेकिन जैसा कि आप कहते हैं, यह डाउनसाइड्स के बिना नहीं है: आज, 10 वर्षों से जावा का उपयोग करने के बाद, मैं नई परियोजनाओं के लिए नोड / जावास्क्रिप्ट या गो का उपयोग करने की प्रवृत्ति रखता हूं, क्योंकि दोनों ही त्वरित विकास की अनुमति देते हैं, और माइक्रो-स्टाइल-शैली आर्किटेक्चर के साथ ये हैं अक्सर पर्याप्त। इस तथ्य को देखते हुए कि Google पहले जावा का उपयोग कर रहा था, लेकिन गो के प्रवर्तक थे, मुझे लगता है कि वे भी ऐसा ही कर रहे होंगे। लेकिन भले ही मैं अब गो और जावास्क्रिप्ट का उपयोग करता हूं, फिर भी मैं जावा के उपयोग और समझने के वर्षों से प्राप्त कई डिजाइन कौशल का उपयोग करता हूं।


1
विशेष रूप से, फ़ोबार भर्ती उपकरण जो Google उपयोग करता है, दो भाषाओं को समाधान के लिए उपयोग करने की अनुमति देता है: जावा और अजगर। मुझे यह दिलचस्प लगता है कि गो एक विकल्प नहीं है। मैं गो पर इस प्रस्तुति पर हुआ था और इसमें जावा और पायथन (साथ ही अन्य भाषाओं) के बारे में कुछ दिलचस्प बिंदु हैं। उदाहरण के लिए एक गोली बिंदु है जो बाहर खड़ा है: "शायद परिणामस्वरूप, गैर-विशेषज्ञ प्रोग्रामर उलझन में हैं" आसानी से "व्याख्या और गतिशील टाइपिंग के साथ" का उपयोग करें। पढ़ने लायक।
जिम्मीजम्स

@JimmyJames सिर्फ स्लाइड में कह रहा है 'विशेषज्ञों के हाथों में, वे महान हैं' - सवाल में समस्या का अच्छा सारांश
टॉम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.