जावा 7 में स्ट्रिंग्स पर स्विच करने का क्या लाभ है?


19

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

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

और IDE टूल और कोडिंग के पढ़ने-लिखने के अनुपात के साथ, मैं स्ट्रिंग मानों को पार करने की तुलना में एक अतिरिक्त Enum उत्पन्न करने में बहुत खुश हूं।

प्रोग्रामर के रूप में वे हमारे लिए क्या लाभ लाते हैं? कम बॉयलर-प्लेट?

यह महसूस नहीं होता है कि इस सुविधा के लिए भाषा रो रही थी। हालांकि हो सकता है कि एक उपयोग-मामला हो, जिसकी मैं देख रहा हूं।


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

@PieterB यकीनन हालांकि, एक Enum हालांकि वर्कअराउंड होने के बजाय शब्दार्थ मान जोड़ रहा है, जो टाइप-सेफ्टी लाता है (उदाहरण के लिए एक टाइपो बग के लिए अग्रणी के बजाय संकलन समय पर पकड़ा जाएगा)। यह हमें स्ट्रिंग के अन्य उदाहरणों का उपयोग करने की भी अनुमति देता है, जैसा कि उस संदर्भ में उपयोग किया जाता है , उस स्ट्रिंग के अन्य उपयोगों को प्रभावित किए बिना (जो कि डोमेन वस्तुओं के साथ अक्सर हो सकता है।)
एक और

जवाबों:


12

जहाँ तक मैं बता सकता हूँ, सवाल यह है कि स्ट्रिंग स्थिरांक को एनम में लपेटना भाषा उपयोगकर्ताओं की जरूरतों को पूरा करने के लिए पर्याप्त नहीं माना गया है। यह JDK 7 (प्रोजेक्ट कॉइन) मेलिंग सूची में घोषित आधिकारिक फीचर प्रस्ताव में संबोधित किया गया है ।

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

मुख्य सहायक: क्या प्रस्ताव को एक अनुकूल परिवर्तन बनाता है?

निरंतर स्ट्रिंग मानों के एक सेट के आधार पर चयनित संचालन के लिए अधिक नियमित कोडिंग पैटर्न का उपयोग किया जा सकता है; नए निर्माण का अर्थ जावा डेवलपर्स के लिए स्पष्ट होना चाहिए।

मुख्य लाभ: यदि प्रस्ताव को अपनाया जाता है तो मंच बेहतर क्यों है?

स्ट्रिंग-आधारित प्रेषण कोड के लिए संभावित बेहतर प्रदर्शन।

मुख्य कार्यक्रम: हमेशा एक लागत होती है।

कुछ ने संकलक के लिए कार्यान्वयन और परीक्षण जटिलता को बढ़ा दिया।

ALTERNATIVES: क्या लाभ और फायदे किसी तरह से बिना भाषा परिवर्तन के हो सकते हैं?

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


बोल्ड भाग काफी आश्चर्य की बात है
साइमन बर्गोट

1
@ मेरे लिए अच्छी तरह से व्यक्तिगत रूप से यह अप्रत्यक्ष उपचार के रूप में पढ़ता है, "हम C # के लिए प्रतिस्पर्धा को ढीला कर देंगे, अगर हम पूर्व जावा 5 के साथ इस तरह के विचारों से निपटने के तरीकों से चिपके रहेंगे"। :) "पूर्व-जावा 5 तरीकों" के एक उदाहरण के लिए, JDK-1223179 का संदर्भ लें : स्ट्रिंग्स पर स्विच करें - 1995 में सबमिट किया गया और जल्दी से बंद नहीं किया जाएगा जैसे कि W Fix Fix : "अपनी सांस को रोककर न रखें। यह जैसा दिखता है वैसा कुछ भी हमारी योजनाओं में नहीं है। । "
gnat

धन्यवाद, प्रस्ताव में रखे गए कारणों को देखने के लिए बहुत दिलचस्प है। यह कहना अभी भी गलत लगता है कि हम एक प्रोग्राम को "अच्छे कारण के बिना" पेश कर रहे हैं - हम OO प्रोग्रामर हैं! :)
नवदंपति

5
@anotherdave "ऑब्जेक्ट-ओरिएंटेड" केवल इन उद्देश्यों को पूरा करने के प्रकारों को पेश करने का औचित्य सिद्ध करता है। जाहिरा तौर पर, जेसीपी पर प्रचलित राय से पता चला कि स्विच में स्ट्रिंग स्थिरांक के लिए ब्रेनलेस रैपर के रूप में एनम का उपयोग सार्थक के रूप में योग्य नहीं है
gnat

1
वाह, मुझे आश्चर्य है (अच्छे तरीके से) आधिकारिक प्रस्ताव को सक्रिय रूप से ब्लोट का मुकाबला करते हुए देखने के लिए। वह ताज़ा है। जावा में टाइप ब्लोट एक बहुत बड़ी समस्या है।
बेन ली

7

कोड को अधिक पठनीय बनाने के अलावा, if/else ifतुलना के सापेक्ष संभावित प्रदर्शन लाभ हैं । क्या बदलाव सार्थक है यह इस बात पर निर्भर करता है कि आप कितनी तुलना कर रहे हैं। एक स्ट्रिंग स्विच को दो अलग-अलग स्विच निर्देशों के रूप में उत्सर्जित किया जाएगा। पहला हैश कोड पर संचालित होता है, इसलिए यह एक lookupswitchअंततः अंततः O(log n)जटिलता पैदा करता है। दूसरा हमेशा एक आदर्श होता है O(1) tableswitch, इसलिए संयुक्त जटिलता अभी भी है O(log n)if/else ifबयानों की एक एकल, रैखिक श्रृंखला थोड़ा और अधिक O(n)जटिल होती।

यदि आप तीन स्ट्रिंग्स की तुलना में अधिक तुलना कर रहे हैं, तो switchयह संभवतः अधिक पठनीय और कॉम्पैक्ट है। यह बेहतर प्रदर्शन करने की संभावना है, हालांकि आप एक अंतर को नोटिस करने की संभावना नहीं रखते हैं जब तक कि आप एक हॉट कोड पथ पर बड़ी संख्या में तुलना नहीं कर रहे हैं।


1
मैं अधिक पूछ रहा था, हालांकि मैं एक एनम पर स्विच के बजाय एक स्ट्रिंग पर स्विच का उपयोग क्यों करूंगा। मैं एक बड़े if/elseब्लॉक को बुरा अभ्यास मानता हूं , लेकिन फिलहाल मेरे पास एक उपयोग करने के लिए बहुत कारण नहीं हैं।
19

लेकिन फिर कमांड पैटर्न के साथ एक मानचित्र भी एक ही जटिलता के साथ अधिक पठनीयता पैदा करेगा क्योंकि आपके पास कमांड का अतिरिक्त प्रकार है
स्पेसट्रूकर

3

स्ट्रिंग्स के लिए स्विच का उपयोग तब किया जा सकता है जब आपके enumमूल्य बाहर से आते हैं, अर्थात एक डेटाबेस में संग्रहीत होते हैं।

जेडीके 7 में एक और उल्लेखनीय बात switchयह है कि यह if-elseनिर्माणों की तुलना में बहुत अधिक परिपूर्ण है ।

और शीघ्र स्ट्रिंग switchएस के लिए एक अच्छा उपयोग मामला JSON / XML स्ट्रीम पार्सिंग हो सकता है जब आपको नोड और विशेषता प्रकारों पर बहुत सारे स्विच करने की आवश्यकता होती है। मैं इसके लिए कोई बेहतर विकल्प नहीं सोच सकता।


1
"स्ट्रिंग्स के लिए स्विच अपरिवर्तनीय है जब आपके एनम मान बाहर से आते हैं, अर्थात एक डेटाबेस में संग्रहीत होते हैं।": क्या आप इस पर विस्तार से बता सकते हैं? स्विच स्टेटमेंट में स्ट्रिंग्स हार्ड-कोडेड हैं: जैसे ही डेटाबेस में स्ट्रिंग्स बदले जाते हैं, आपका कोड पुराना हो जाता है।
जियोर्जियो

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

2

सादगी

स्विच सपोर्ट में स्ट्रिंग एनम या if-elseलॉजिक में रूपांतरण के बिना डेटा को संसाधित करने के लिए उपयोगी है। कभी-कभी स्ट्रिंग पर स्विच करना आसान होता है।

से JDK 7 (परियोजना सिक्का) मेलिंग सूची पर सुविधा प्रस्ताव ( @gnat जवाब )

ब्याज के प्रति स्ट्रिंग मूल्य में से एक, अपने switchable स्थिरांक के लिए एक दुश्मनी शुरू करना, अच्छे कारण के बिना कार्यक्रम में एक और प्रकार जोड़ देगा ...

यदि -अलग संस्करण

यह छोटा है, लेकिन कई if'sको पढ़ना मुश्किल है। और यह धीमा है।

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

एनम संस्करण

एनमों को परिभाषित करने की आवश्यकता है, यह अच्छा है, लेकिन कुछ समय की आवश्यकता नहीं है।

enum Color {RED, GREEN}

हमेशा की तरह प्रसंस्करण

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - स्विच स्टेटमेंट संस्करण में स्ट्रिंग्स

हम अतिरिक्त प्रकारों को परिवर्तित और परिभाषित किए बिना प्रक्रिया कर सकते हैं।

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
यह प्रश्न को संबोधित नहीं करता है, हालांकि: आप यहां एनमों के बजाय स्ट्रिंग्स का उपयोग क्यों करेंगे?
डेव न्यूटन

0

किसी भी भाषा में अधिकांश सुधार कोड को पढ़ने में आसान बनाना है। मैं किसी भी दिन फैंसी पर पठनीय कोड का पक्ष लेता हूं।

आप इस पर विश्वास नहीं कर सकते हैं, लेकिन कोशिश करें:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

मैं आपके कोड उदाहरण बनाम आपकी टिप्पणियों पर अस्पष्ट हूँ। क्या आप एनम का मतलब किसी ऐसी चीज़ के उदाहरण के रूप में पढ़ रहे हैं, जिसे पढ़ना मुश्किल है?
18

@anotherdave देखें stackoverflow.com/a/338230/2860598

2
यह बहुत ही विरोधाभासी है; आप यह दिखावा कर रहे हैं कि enum में कोई ईमेल फ़ील्ड नहीं होगा, या यह एक वर्ग नहीं होगा।
डेव न्यूटन

4
@ user2860598 यदि आप एक बिंदु बनाने की कोशिश कर रहे हैं, तो प्रासंगिक उदाहरण का उपयोग करें। यह वसा स्ट्रिंग को स्थिर करने वाले पते को भी संबोधित नहीं करता है।
डेव न्यूटन

1
@ user2860598 आपके द्वारा जोड़ा गया उत्तर कह रहा है कि वहाँ शुरू कर दिया गया है और इससे पहले कि वे एनम के साथ "अनुमानित" हो सकते हैं। मेरा कहना था कि एनम का उपयोग अभी भी बेहतर लगता है, यहां तक ​​कि उनके परिचय के साथ भी।
नवद्वीप 16'13

0

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

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

आप अभी भी इस मामले में enums का उपयोग केवल नाम और / या कस्टम स्ट्रिंग प्रदान करके प्राप्त करने की कोशिश करके कर सकते हैं-> Enum दिनचर्या लेकिन कभी-कभी यह संभव नहीं है या सिर्फ व्यावहारिक नहीं है (जब आपको बहुत सारे enums बनाने होंगे)

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


यदि आप बाहरी डेटा के साथ काम कर रहे हैं, और आप पहले से ही यह जानने के लिए पर्याप्त हैं कि आपको अपने ifबयानों में क्या चाहिए, तो आपको इसे वैसे भी लपेटना चाहिए , जिसका अर्थ है कि आप अभी भी enums, या कमांड पैटर्न आदि का उपयोग कर सकते हैं
डेव न्यूटन

@DaveNewton हाँ, आप अभी भी enums का उपयोग कर सकते हैं, लेकिन जैसा कि मैंने अपने जवाब में कहा था, कभी-कभी यह व्यावहारिक नहीं होता है, जैसे कि आप अपने कोड में केवल एक बार उपयोग किए जाने वाले Enums की भूख पैदा कर सकते हैं।

@dimoniy लेकिन अगर आपको 100s Enum मान बनाने हैं, तो इसका मतलब यह नहीं होगा कि स्विच विकल्प के साथ आपके पास 100s केस स्टेटमेंट होना चाहिए? अगर वहाँ हैं कि कई चर, मैं निश्चित रूप से प्रकार की सुरक्षा पसंद करेंगे।
नवद्वीप 16'13

0

जब आप Stringsस्विच स्टेटमेंट में उपयोग करते हैं तो मुझे लगता है कि यह क्लीनर और पठनीय कोड के साथ सहमत नहीं है और लगता है कि यह एक बुरा प्रोग्रामिंग अभ्यास है। यदि आप उस मूल्य को बदलते हैं जिसका उपयोग आप स्टोर करने के लिए करते हैं, तो आपको इसे हर स्विच या if -ifif occurance को बदलना होगा। यह अच्छा नहीं है क्योंकि आप अपने कोड के प्रत्येक बायर को हार्डकोडेड मान डाल रहे हैं। यदि आप एक दिन इन कठोर कोडित मूल्यों को बदलने का निर्णय लेते हैं तो आप क्या करने जा रहे हैं? इसकी प्रत्येक प्रति खोजें और बदलें?

यदि आपके पास कुछ हार्डकोड मान हैं जो आप करते हैं-ifif कथन, तो उनके लिए निरंतर आदिम मूल्यों का उपयोग करना जावा 1.5 से पहले सिर्फ इसलिए बेहतर है क्योंकि यह टाइप सुरक्षा लाता है।

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

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


-1

यदि आप जानते हैं कि कौन सी जानकारी आ रही है और यह केवल 5 राज्यों में हो सकती है तो a का उपयोग करें Enum। हालाँकि, यदि संभावित स्थिति 9000 से अधिक हो सकती है और आपको केवल 42 खोजने की आवश्यकता है, तो स्विच का उपयोग करना बेहतर है क्योंकि आप उन सभी राज्यों को टाइप करना नहीं चाहते हैं।

एक एनम ज्यादातर परिस्थितियों में सबसे अधिक पसंद करता है जब तक कि संभव नहीं है कि राज्य अज्ञात हैं या बहुत कुछ है और आप केवल कुछ के बारे में परवाह करते हैं।

लेकिन उन्होंने इसे अब क्यों पेश किया? यह सिर्फ एक बदलाव था जो क्लीनर कोड के लिए अनुमति देता था।

1.5 में उन्होंने आपको Enums के लिए भी कस्टम बॉडी बनाने की अनुमति दी।


लेकिन क्या आप सिर्फ एक Enum राज्य के लिए अन्य 8958 संभावित मान निर्दिष्ट नहीं करेंगे?
नवद्वीप 16'13

@anotherdave यह जहां है defaultमें switchखेलने के लिए में आता है। मुझे नहीं पता है कि आपके पास एक डिफ़ॉल्ट स्थिति हो सकती है Enum, जब तक कि आप एक डिफ़ॉल्ट राज्य नहीं बनाते हैं लेकिन तब यह कोड बस फूला हुआ हो जाता है, जबकि switchउपयोग करने के लिए बहुत क्लीनर है।

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