मैं स्थैतिक मानचित्र को कैसे आरंभ कर सकता हूं?


1131

आप Mapजावा में एक स्टेटिक को कैसे इनिशियलाइज़ करेंगे ?

विधि एक: स्टैटिक इनिशियलर
मेथड दो: उदाहरण इनिशियलर (अनाम उपवर्ग) या कोई अन्य विधि?

प्रत्येक का भला - बुरा क्या है?

यहाँ दो तरीकों को दर्शाने वाला एक उदाहरण दिया गया है:

import java.util.HashMap;
import java.util.Map;

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

2
जावा 8 में एक नक्शे को आरंभ करने के लिए: stackoverflow.com/a/37384773/1216775
akhil_mittal

2
कृपया, कभी भी डबल ब्रेस इनिशियलाइज़ेशन का उपयोग न करें - यह एक हैक है, और मेमोरी को लीक करने और अन्य समस्याओं का कारण बनने का एक आसान तरीका है।
dimo414

जावा 9? अगर प्रविष्टियाँ Map.ofMap.ofEntries
गिनें

जवाबों:


1106

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

आप स्थैतिक आरंभक का उपयोग करके एक अपरिवर्तनीय मानचित्र भी बना सकते हैं:

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

10
यह वह मुहावरा है जिसका मैंने वर्षों से उपयोग किया है और मैंने कभी किसी पर नज़र नहीं रखी। मैं unmodifiable स्थिर सेट और सूचियों के लिए भी यही करता हूं।
jasonmp85

3
मैं एक स्ट्रिंग कुंजी के साथ एक HashMap <स्ट्रिंग, स्ट्रिंग> को कैसे संभालूंगा। मैप ऑब्जेक्ट मुझे स्ट्रिंग की अनुमति नहीं देता है इसलिए मैं अनमॉडिफ़िबिलिटी मैप () का उपयोग नहीं कर सकता। मुझे लगता है कि हाशपॅप को कास्ट करना उद्देश्य को भी हरा देगा। कोई विचार?
ल्यूक

30
@ मुझे गंभीरता से संदेह है कि एंड्रॉइड में इस तरह की सीमा है। इसके कोई भी मायने नहीं हैं। एक त्वरित खोज ने इस सवाल को यहां (और कई अन्य) पाया जो आपको लगता है कि आप एंड्रॉइड में एक मैप ऑब्जेक्ट के लिए स्ट्रिंग कुंजी का उपयोग कर सकते हैं।
mluisbrown

11
इसलिए कोई और जांच करने के लिए परेशान नहीं करता, मैं पुष्टि कर सकता हूं कि एंड्रॉइड पर मैप ऑब्जेक्ट के लिए स्ट्रिंग कुंजी का उपयोग करने में कोई समस्या नहीं है।
जॉर्डन

11
जॉर्डन: यह अब एक पुराना विषय है, लेकिन मुझे संदेह है कि @ ल्यूक एक मानचित्र में एक कुंजी के रूप में एक स्ट्रिंग का उपयोग करने की कोशिश कर रहा था जिसमें एक अलग कुंजी प्रकार था, उदाहरण के लिए नक्शा <पूर्णांक, स्ट्रिंग>।
दुखी चर

445

मुझे स्थैतिक, अपरिवर्तनीय मानचित्र को आरम्भ करने का अमरूद तरीका पसंद है :

static final Map<Integer, String> MY_MAP = ImmutableMap.of(
    1, "one",
    2, "two"
);

जैसा कि आप देख सकते हैं, यह बहुत संक्षिप्त है (सुविधाजनक कारखाने विधियों के कारण ImmutableMap)।

यदि आप चाहते हैं कि मानचित्र में 5 से अधिक प्रविष्टियाँ हों, तो आप अब उपयोग नहीं कर सकते ImmutableMap.of()। इसके बजाय, ImmutableMap.builder()इन पंक्तियों के साथ प्रयास करें :

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
    .put(1, "one")
    .put(2, "two")
    // ... 
    .put(15, "fifteen")
    .build();

अमरूद की अपरिवर्तनीय संग्रह उपयोगिताओं के लाभों के बारे में अधिक जानने के लिए, अमरुद उपयोगकर्ता गाइड में मौजूद अपरिवर्तनीय संग्रह देखें ।

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


अद्यतन (2015) : जैसा कि जावा 8 के लिए है , ठीक है, मैं अभी भी अमरूद दृष्टिकोण का उपयोग करूंगा क्योंकि यह किसी भी अन्य तरीके से क्लीनर है। यदि आप अमरूद की निर्भरता नहीं चाहते हैं, तो एक पुरानी पुरानी विधि पर विचार करें । दो आयामी सरणी और स्ट्रीम एपीआई के साथ हैक बहुत ही बदसूरत है यदि आप मुझसे पूछते हैं, और बदसूरत हो जाता है यदि आपको एक ऐसा मानचित्र बनाने की आवश्यकता है जिसकी कुंजी और मान एक ही प्रकार के नहीं हैं (जैसे Map<Integer, String>प्रश्न में)।

जावा 8 के संबंध में सामान्य रूप से अमरूद के भविष्य के लिए, लुई वासरमैन ने 2014 में यह वापस कहा , और 2016 में [ अद्यतन ] यह घोषणा की गई कि अमरूद 21 को जावा 8 की आवश्यकता होगी और ठीक से समर्थन करेगी


अपडेट (2016) : जैसा कि टैगिर वलेव बताते हैं , जावा 9 अंत में संग्रह के लिए सुविधा कारखाने के तरीकों को जोड़कर शुद्ध जेडीके के अलावा कुछ भी नहीं करने के लिए यह साफ कर देगा :

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);

21
लगता है जैसे हमारे साथी एसओ प्रवेश ने आदरणीय "सबसे उपयोगी मुक्त तृतीय पक्ष जावा पुस्तकालय" प्रश्न को हटा दिया है, जिससे मैंने लिंक किया था। :( उन्हें धिक्कार है।
जोनिक

2
मैं सहमत हूं, यह निरंतर मानचित्र को शुरू करने का सबसे अच्छा तरीका है। न केवल अधिक पठनीय बल्कि संग्रहणीय भी। चूंकि modifiableMap अंतर्निहित मानचित्र का केवल-पढ़ने का दृश्य देता है (जिसे अभी भी संशोधित किया जा सकता है)।
crunchdog

11
मैं अब हटाए गए प्रश्नों (10k + प्रतिनिधि के साथ) देख सकता हूं, इसलिए यहां 'सबसे उपयोगी मुक्त तृतीय-पक्ष जावा पुस्तकालयों' की एक प्रति है । यह केवल पहला पृष्ठ है, लेकिन कम से कम आप ऊपर वर्णित अमरूद संसाधनों को पा सकते हैं ।
जोनिक

2
मैं वास्तव में इस दृष्टिकोण को पसंद करता हूं, हालांकि यह जानना फायदेमंद है कि इसे अतिरिक्त निर्भरता के बिना कैसे करना है।
रिंच

2
JEP 186 अभी भी बंद नहीं हुआ है, इसलिए यह संग्रह शाब्दिक से संबंधित नई सुविधाओं को प्रस्तुत कर सकता है
साइबर

182

मै इस्तेमाल करूंगा:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  1. यह एक अनाम वर्ग से बचता है, जिसे मैं व्यक्तिगत रूप से एक बुरी शैली मानता हूं और इससे बचता हूं
  2. यह मानचित्र के निर्माण को अधिक स्पष्ट बनाता है
  3. यह मानचित्र को अपरिवर्तनीय बनाता है
  4. जैसे MY_MAP निरंतर है, मैं इसे निरंतर की तरह नाम दूंगा

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

यह मेरे लिए कभी नहीं हुआ कि आप ऐसा कर सकें।
रोमुलसुन्नर

181

Java 5 इसे और अधिक कॉम्पैक्ट सिंटैक्स प्रदान करता है:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};

46
उस तकनीक को डबल ब्रेस इनिशियलाइज़ेशन कहा जाता है: stackoverflow.com/questions/1372113/… यह एक विशेष जावा 5 सिंटैक्स नहीं है, यह एक उदाहरण इनिलाइज़र के साथ अनाम वर्ग के साथ सिर्फ एक चाल है।
जेसपर

13
डबल ब्रेस इनिशियलाइज़ेशन के संबंध में त्वरित प्रश्न: ऐसा करते समय, ग्रहण एक लापता सीरियल आईडी के बारे में चेतावनी जारी करता है। एक तरफ, मैं यह नहीं देखता कि इस विशिष्ट मामले में एक सीरियल आईडी की आवश्यकता क्यों होगी, लेकिन दूसरी ओर, मुझे आमतौर पर चेतावनी चेतावनी पसंद नहीं है। इस पर आपके विचार क्या हैं?
nbarraille

8
यही कारण है कि के @nbarraille क्योंकि HashMap implements Serializable। चूंकि आप वास्तव में इस "ट्रिक" का उपयोग करके हाशप का उपवर्ग बनाते हैं, इसलिए आप स्पष्ट रूप से एक सीरियल क्लास बना सकते हैं। और इसके लिए आपको एक सीरियलयूआईडी की आपूर्ति करनी चाहिए।
दोपहर

5
Double brace initialization can cause memory leaks when used from a non-static context, because the anonymous class created will maintain a reference to the surrounding object. It has worse performance than regular initialization because of the additional class loading required. It can cause equals() comparisons to fail, if the equals() method does not accept subclasses as parameter. And finally, pre Java 9 it cannot be combined with the diamond operator, because that cannot be used with anonymous classes.-
इंटेलीज

3
@MarkJeronimus - सुझाव उपयोग है एक स्थिर संदर्भ। प्रदर्शन बदतर हो सकता है, लेकिन तब नहीं जब यह सांख्यिकीय रूप से परिभाषित नक्शे की एक छोटी संख्या के साथ काम कर रहा हो। HashMap.equalsमें परिभाषित किया गया है AbstractMapऔर मानचित्र के किसी भी उपवर्ग पर काम करता है , ताकि यहां चिंता न हो। हीरा ऑपरेटर की बात कष्टप्रद है, लेकिन जैसा कि अब उल्लेख किया गया है।
जूल्स

95

दूसरी विधि का एक फायदा यह है कि आप इसे इस बात के साथ लपेट सकते हैं Collections.unmodifiableMap()कि बाद में संग्रह को अपडेट करने के लिए कुछ भी नहीं किया जा रहा है:

private static final Map<Integer, String> CONSTANT_MAP = 
    Collections.unmodifiableMap(new HashMap<Integer, String>() {{ 
        put(1, "one");
        put(2, "two");
    }});

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!

3
क्या आप नए ऑपरेटर को स्थिर {} ब्लॉक में ले जाकर और उसे लपेटकर पहली विधि में आसानी से नहीं कर सकते हैं?
पैट्रिक

2
मैं कंस्ट्रक्टर कॉल को स्टैटिक इनिशियलाइज़्ड में वैसे भी स्थानांतरित करूँगा। और कुछ भी सिर्फ अजीब लग रहा है।
टॉम हैटिन -

2
किसी भी विचार का प्रदर्शन वहां एक अनाम वर्ग का उपयोग करने से हो सकता है जो एक ठोस वर्ग के विपरीत हो?
किप

62

यहाँ एक जावा 8 एक लाइन स्थैतिक मानचित्र आरंभीकरण है:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =
    Arrays.stream(new String[][] {
        { "txt", "text/plain" }, 
        { "html", "text/html" }, 
        { "js", "application/javascript" },
        { "css", "text/css" },
        { "xml", "application/xml" },
        { "png", "image/png" }, 
        { "gif", "image/gif" }, 
        { "jpg", "image/jpeg" },
        { "jpeg", "image/jpeg" }, 
        { "svg", "image/svg+xml" },
    }).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

संपादित करें: Map<Integer, String>प्रश्न में एक के रूप में आरंभ करने के लिए, आपको कुछ इस तरह की आवश्यकता होगी:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
        {1, "one"},
        {2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

संपादित करें (2): i_am_zero द्वारा एक बेहतर, मिश्रित-प्रकार-सक्षम संस्करण है जो new SimpleEntry<>(k, v)कॉल की एक धारा का उपयोग करता है । उस उत्तर को देखें: https://stackoverflow.com/a/37384773/3950982


7
मैंने एक ऐसे संस्करण को जोड़ने के लिए स्वतंत्रता ली, जो प्रश्न और अन्य उत्तरों के बराबर है: एक मानचित्र डालें जिसकी कुंजियाँ और मान भिन्न प्रकार के हैं (ऐसा String[][]नहीं होगा, Object[][]इसकी आवश्यकता है)। IMHO, यह दृष्टिकोण बदसूरत है (यहां तक ​​कि जातियों के साथ भी अधिक) और याद रखना मुश्किल है; खुद इसका इस्तेमाल नहीं करेंगे।
जोनीक

57

Map.of जावा में 9+

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

देखें JEP 269 जानकारी के लिए। JDK 9 सितंबर 2017 में सामान्य उपलब्धता पर पहुंच गया ।


7
या यदि आप 10 से अधिक कुंजी-मूल्य वाले जोड़े चाहते हैं, तो आप उपयोग कर सकते हैंMap.ofEntries
ZhekaKozlov

8
यह साफ है और सब है, जब तक आपको पता है कि यह कैसे लागू किया गया था
मध्य

Ugh thats बहुत दुखी - ऐसा लगता है कि यह केवल 10 प्रविष्टियों का समर्थन करता है, जिसके बाद आपको इनट्रीज़ का उपयोग करने की आवश्यकता होती है। लंगड़ा।
सोमैया कुम्बरिया

2
जेडीके में कार्यान्वयन की सफाई तब तक मायने नहीं रखती है जब तक यह काम करता है और अनुबंध को संतुष्ट करता है। किसी भी ब्लैक बॉक्स की तरह, कार्यान्वयन विवरण हमेशा भविष्य में तय किया जा सकता है यदि वास्तव में जरूरत हो ...
1919 vikingsteve

@ यह जावा में ऐसा करने का एकमात्र प्रकार है।
ल्यूक हचिसन

44

जावा ९

हम प्रत्येक प्रविष्टि बनाने के लिए Map.ofEntriesकॉलिंग Map.entry( k , v )का उपयोग कर सकते हैं ।

import static java.util.Map.entry;
private static final Map<Integer,String> map = Map.ofEntries(
        entry(1, "one"),
        entry(2, "two"),
        entry(3, "three"),
        entry(4, "four"),
        entry(5, "five"),
        entry(6, "six"),
        entry(7, "seven"),
        entry(8, "eight"),
        entry(9, "nine"),
        entry(10, "ten"));

हम यहांMap.of उनके उत्तर में टैगिर द्वारा सुझाए गए अनुसार भी उपयोग कर सकते हैं, लेकिन हमारे पास 10 से अधिक प्रविष्टियों का उपयोग नहीं हो सकता है Map.of

जावा 8 (नीट सॉल्यूशन)

हम मानचित्र प्रविष्टियों की एक स्ट्रीम बना सकते हैं। हम पहले से ही के दो कार्यान्वयन है Entryमें java.util.AbstractMapजो कर रहे हैं SimpleEntry और SimpleImmutableEntry । इस उदाहरण के लिए हम पूर्व का उपयोग कर सकते हैं:

import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
            new SimpleEntry<>(1, "one"),
            new SimpleEntry<>(2, "two"),
            new SimpleEntry<>(3, "three"),
            new SimpleEntry<>(4, "four"),
            new SimpleEntry<>(5, "five"),
            new SimpleEntry<>(6, "six"),
            new SimpleEntry<>(7, "seven"),
            new SimpleEntry<>(8, "eight"),
            new SimpleEntry<>(9, "nine"),
            new SimpleEntry<>(10, "ten"))
            .collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));

2
new SimpleEntry<>()स्टैटिक की तुलना में यह तरीका बहुत कम पठनीय है put(): /
दानोन

32

ग्रहण संग्रह के साथ , निम्नलिखित में से सभी काम करेंगे:

import java.util.Map;

import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;

public class StaticMapsTest
{
    private static final Map<Integer, String> MAP =
        Maps.mutable.with(1, "one", 2, "two");

    private static final MutableMap<Integer, String> MUTABLE_MAP =
       Maps.mutable.with(1, "one", 2, "two");


    private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();


    private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
        Maps.mutable.with(1, "one", 2, "two").asSynchronized();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").toImmutable();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
        Maps.immutable.with(1, "one", 2, "two");
}

आप ग्रहण संग्रहों के साथ आदिम मानचित्रों को सांख्यिकीय रूप से आरंभ कर सकते हैं।

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;

public class StaticPrimitiveMapsTest
{
    private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two");

    private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asUnmodifiable();

    private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asSynchronized();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .toImmutable();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
            IntObjectMaps.immutable.<String>empty()
                    .newWithKeyValue(1, "one")
                    .newWithKeyValue(2, "two");
} 

नोट: मैं एक्लिप्स कलेक्शंस के लिए कमिट हूं


1
मैं वास्तव में चाहता हूं कि ग्रहण संग्रह जावा के लिए डिफ़ॉल्ट संग्रह पुस्तकालय था। मुझे यह अमरूद + जेसीएल से बहुत अधिक पसंद है।
केनी कैसन

29

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

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}

1
किस स्थिति में आप एक अनाम उप-वर्ग का उपयोग तब हैशमैप को इनिशियलाइज़ करने के लिए करेंगे?
डॉगबेन

6
एक संग्रह को शुरू करने के लिए कभी नहीं।
एलजेन्सो

क्या आप बता सकते हैं कि एक अनाम सबक्लास बनाने की तुलना में स्टैटिक इनिशियलाइज़र का उपयोग करना बेहतर विकल्प क्यों है?
leba-lev

3
@rookie स्थैतिक init के पक्ष में अन्य उत्तरों में कई कारण दिए गए हैं। यहां लक्ष्य है प्रारंभ करने में, तो क्यों उपवर्गीकरण में लाने के लिए, कुछ ही कीस्ट्रोक को बचाने के लिए हो सकता है सिवाय? (यदि आप कीस्ट्रोक्स पर बचत करना चाहते हैं, तो निश्चित रूप से जावा एक प्रोग्रामिंग भाषा के रूप में एक अच्छा विकल्प नहीं है।) जावा में प्रोग्रामिंग करते समय अंगूठे का एक नियम मैं उपयोग करता हूं: जितना संभव हो उतना कम उप-वर्ग (और जब कभी इसे टाला नहीं जा सकता)।
eljenso

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

18

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

अपडेट: इस लाइब्रेरी का नाम अब अमरूद रखा गया है ।


17

मुझे अनाम वर्ग पसंद है, क्योंकि इससे निपटना आसान है:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});

12
public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

यदि हम एक से अधिक स्थिरांक घोषित करते हैं, तो वह कोड स्टेटिक ब्लॉक में लिखा जाएगा और भविष्य में इसे बनाए रखना कठिन है। इसलिए अनाम वर्ग का उपयोग करना बेहतर है।

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

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


10

मैं दृढ़ता से "डबल ब्रेस इनिशियलाइज़ेशन" स्टाइल को स्टैटिक ब्लॉक स्टाइल पर सुझा सकता था।

कोई टिप्पणी कर सकता है कि उन्हें अनाम वर्ग, ओवरहेड, प्रदर्शन आदि पसंद नहीं है।

लेकिन मुझे लगता है कि कोड पठनीयता और स्थिरता है। इस दृष्टि से, मुझे लगता है कि एक डबल ब्रेस एक बेहतर कोड शैली है, बल्कि स्थिर विधि है।

  1. तत्व नेस्टेड और इनलाइन हैं।
  2. यह अधिक OO है, प्रक्रियात्मक नहीं है।
  3. प्रदर्शन प्रभाव वास्तव में छोटा है और इसे नजरअंदाज किया जा सकता है।
  4. बेहतर आईडीई रूपरेखा समर्थन (बल्कि कई अनाम स्थैतिक {} ब्लॉक)
  5. आपने उन्हें संबंध लाने के लिए टिप्पणी की कुछ पंक्तियों को सहेजा है।
  6. अपवाद और बायोटेक ऑप्टिमाइज़र से असंयुक्त वस्तु के संभावित तत्व रिसाव / उदाहरण सीसा को रोकें।
  7. स्थैतिक ब्लॉक के निष्पादन के आदेश के बारे में कोई चिंता नहीं है।

इसके अलावा, यह आपको अनाम वर्ग के GC के बारे में जानकारी देता है, आप हमेशा इसका उपयोग करके एक सामान्य HashMap में परिवर्तित कर सकते हैं new HashMap(Map map)

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


8

हमेशा की तरह अपाचे-कॉमन्स के पास उचित तरीका है MapUtils.putAll (मैप, ऑब्जेक्ट []]) :

उदाहरण के लिए, रंग मानचित्र बनाने के लिए:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });

मैं सभी बिल्ड में अपाचे कॉमन्स शामिल करता हूं, इसलिए Arrays.asMap( ... )सादे जावा में एक विधि की दुर्भाग्यपूर्ण अनुपस्थिति में , मुझे लगता है कि यह सबसे अच्छा समाधान है। पहिया को फिर से चालू करना आमतौर पर मूर्खतापूर्ण है। बहुत मामूली नकारात्मक यह है कि जेनरिक के साथ इसे अनियंत्रित रूपांतरण की आवश्यकता होगी।
माइक कृंतक

@mikerodent 4.1 संस्करण सामान्य है: सार्वजनिक स्थैतिक <K, V> मानचित्र <K, V> putAll (अंतिम मानचित्र <K, V> मानचित्र, अंतिम वस्तु [] सरणी)
agad

टीएक्स ... हाँ, मैं 4.1 का उपयोग कर रहा हूं, लेकिन मुझे अभी भी SuppressWarnings( unchecked )ग्रहण में एक पंक्ति के साथ है जैसेMap<String, String> dummy = MapUtils.putAll(new HashMap<String, String>(), new Object[][]... )
माइक कृंतक

@mikerodent ऑब्जेक्ट [] [] के कारण नहीं है ? अपडेटेड अनस्वेर्स देखें - मुझे ग्रहण में कोई चेतावनी नहीं है।
अगाद

कितना अजीब ... यहां तक ​​कि जब मैं जाता String[][]हूं तो मुझे "चेतावनी" मिलती है! और निश्चित रूप से केवल तभी काम करता है जब आपकी Kऔर Vसमान कक्षा हो। मुझे लगता है कि आपने (ग्रहण में) "अनियंत्रित रूपांतरण" को अपने ग्रहण सेटअप में "अनदेखा" नहीं किया है?
माइक कृंतक

7

यहाँ मेरा पसंदीदा है जब मैं नहीं चाहता है (या नहीं कर सकते हैं) अमरूद का उपयोग करें ImmutableMap.of(), या अगर मैं एक परिवर्तनशील जरूरत है Map:

public static <A> Map<String, A> asMap(Object... keysAndValues) {
    return new LinkedHashMap<String, A>() {{
        for (int i = 0; i < keysAndValues.length - 1; i++) {
            put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
        }
    }};
}

यह बहुत कॉम्पैक्ट है, और यह आवारा मूल्यों (यानी एक मूल्य के बिना अंतिम कुंजी) को अनदेखा करता है।

उपयोग:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));

7

यदि आप unmodifiable map चाहते हैं, तो आखिरकार java 9 ने इंटरफ़ेस के ofलिए एक बढ़िया फैक्ट्री विधि जोड़ी Map। इसी तरह की विधि सेट, सूची में भी जोड़ी जाती है।

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");


6

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

नोट: यह प्रश्न मानचित्र को अप्रमाणिक बनाने के बारे में कुछ नहीं कहता है, इसलिए मैं इसे छोड़ दूंगा, लेकिन यह जानता हूं कि यह आसानी से किया जा सकता है Collections.unmodifiableMap(map)

पहली टिप

पहली टिप यह है कि आप नक्शे का स्थानीय संदर्भ बना सकते हैं और आप इसे SHORT नाम दे सकते हैं:

private static final Map<Integer, String> myMap = new HashMap<>();
static {
    final Map<Integer, String> m = myMap; // Use short name!
    m.put(1, "one"); // Here referencing the local variable which is also faster!
    m.put(2, "two");
    m.put(3, "three");
}

दूसरा सिरा

दूसरी टिप यह है कि आप प्रविष्टियों को जोड़ने के लिए एक सहायक विधि बना सकते हैं; यदि आप चाहें तो इस सहायक विधि को भी सार्वजनिक कर सकते हैं:

private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
    p(1, "one"); // Calling the helper method.
    p(2, "two");
    p(3, "three");
}

private static void p(Integer k, String v) {
    myMap2.put(k, v);
}

यहाँ सहायक विधि फिर से प्रयोग करने योग्य नहीं है, क्योंकि यह केवल तत्वों को जोड़ सकती है myMap2। इसे फिर से प्रयोग करने योग्य बनाने के लिए, हम मानचित्र को सहायक विधि का एक पैरामीटर बना सकते हैं, लेकिन तब आरंभीकरण कोड कम नहीं होगा।

तीसरा सिरा

3 टिप यह है कि आप पॉपुलेटिंग कार्यक्षमता के साथ फिर से उपयोग करने योग्य बिल्डर जैसे सहायक वर्ग बना सकते हैं। यह वास्तव में एक सरल, 10-लाइन हेल्पर क्लास है जो टाइप-सेफ है:

public class Test {
    private static final Map<Integer, String> myMap3 = new HashMap<>();
    static {
        new B<>(myMap3)   // Instantiating the helper class with our map
            .p(1, "one")
            .p(2, "two")
            .p(3, "three");
    }
}

class B<K, V> {
    private final Map<K, V> m;

    public B(Map<K, V> m) {
        this.m = m;
    }

    public B<K, V> p(K k, V v) {
        m.put(k, v);
        return this; // Return this for chaining
    }
}

5

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

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

EDIT: टिप्पणियों में सही ढंग से बताया गया कि यह एक स्थिर वर्ग है। जाहिर है मैंने इसे काफी करीब से नहीं पढ़ा था। हालांकि मेरी टिप्पणी करते पास अब भी अज्ञात भीतरी वर्गों के लिए लागू होते हैं।


3
इस विशेष मामले में यह स्थिर है, इसलिए कोई बाहरी उदाहरण नहीं है।
टॉम हॉल्टिन -

संभवतः XStream को इस तरह सामान को क्रमबद्ध करने की कोशिश नहीं करनी चाहिए (यह स्थिर है। आपको एक स्थिर चर को क्रमबद्ध करने की आवश्यकता क्यों होगी?)
jasonmp85

5

यदि आप कुछ सुव्यवस्थित और अपेक्षाकृत सुरक्षित चाहते हैं, तो आप बस संकलन-टाइम प्रकार की जाँच को रन-टाइम में शिफ्ट कर सकते हैं:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

इस कार्यान्वयन को किसी भी त्रुटि को पकड़ना चाहिए:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}

4

जावा 8 के साथ मैं निम्नलिखित पैटर्न का उपयोग करने के लिए आया हूं:

private static final Map<String, Integer> MAP = Stream.of(
    new AbstractMap.SimpleImmutableEntry<>("key1", 1),
    new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

यह सबसे ट्रिक और थोड़ा गोल चक्कर नहीं है, लेकिन

  • इसके बाहर किसी चीज की आवश्यकता नहीं है java.util
  • यह महत्वपूर्ण है और आसानी से कुंजी और मूल्य के लिए विभिन्न प्रकारों को समायोजित करता है।

यदि आवश्यक हो, तो toMapकोई मानचित्र के प्रकार को निर्दिष्ट करने के लिए मानचित्र आपूर्तिकर्ता सहित हस्ताक्षर का उपयोग कर सकता है ।
ज़्रवन

4

यदि आपको केवल मानचित्र में एक मान जोड़ने की आवश्यकता है तो आप Collections.singletonMap का उपयोग कर सकते हैं :

Map<K, V> map = Collections.singletonMap(key, value)

4

आप उपयोग कर सकते हैं StickyMapऔर MapEntryसे Cactoos :

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);

4

आपके दूसरे दृष्टिकोण (डबल ब्रेस इनिशियलाइज़ेशन) को एक विरोधी पैटर्न माना जाता है , इसलिए मैं पहले दृष्टिकोण के लिए जाऊंगा।

स्थैतिक मानचित्र को इनिशियलाइज़ करने का एक और आसान तरीका है इस यूटिलिटी फंक्शन का उपयोग करना:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {
    Map<K, V> map = new HashMap<>(keyValues.length / 2);

    for (int index = 0; index < keyValues.length / 2; index++) {
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    }

    return map;
}

Map<Integer, String> map1 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");

नोट: Java 9आप Map.of का उपयोग कर सकते हैं


3

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

public class MyClass {
    private static final Map<Integer, String> myMap = prepareMap();

    private static Map<Integer, String> prepareMap() {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "one");
        hashMap.put(2, "two");

        return hashMap;
    }
}

3

मैंने किसी भी उत्तर में पोस्ट किए गए दृष्टिकोण का उपयोग नहीं किया है (और पसंद करने के लिए बड़े हो गए हैं), इसलिए यहां यह है:

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

इसके बजाय, मैं आरंभीकरण पसंद करता हूं जो इस तरह दिखता है:

map(
    entry("keyA", "val1"),
    entry("keyB", "val2"),
    entry("keyC", "val3")
);

दुर्भाग्य से, ये विधियां मानक जावा लाइब्रेरी का हिस्सा नहीं हैं, इसलिए आपको एक उपयोगिता पुस्तकालय बनाने की आवश्यकता होगी (या उपयोग) जो निम्नलिखित विधियों को परिभाषित करता है:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
 public static <K,V> Map.Entry<K,V> entry(K key, V val)

(आप विधि के नाम को उपसर्ग करने की आवश्यकता से बचने के लिए 'आयात स्थैतिक' का उपयोग कर सकते हैं)

मुझे अन्य संग्रह (सूची, सेट, सॉर्टसेट, सॉर्टपैड, आदि) के लिए इसी तरह के स्थिर तरीके प्रदान करना उपयोगी लगा।

यह जोंस ऑब्जेक्ट इनिशियलाइज़ेशन जितना अच्छा नहीं है, लेकिन यह उस दिशा में एक कदम है, जहाँ तक पठनीयता का संबंध है।


3

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

सौभाग्य से, फैक्ट्री के तरीकों का उपयोग करके जावा में मानचित्र शाब्दिकों के व्यवहार को अनुमानित करना संभव है ।

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

public class LiteralMapFactory {

    // Creates a map from a list of entries
    @SafeVarargs
    public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
        LinkedHashMap<K, V> map = new LinkedHashMap<>();
        for (Map.Entry<K, V> entry : entries) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }
    // Creates a map entry
    public static <K, V> Map.Entry<K, V> entry(K key, V value) {
        return new AbstractMap.SimpleEntry<>(key, value);
    }

    public static void main(String[] args) {
        System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
    }
}

आउटपुट:

{a = १, बी = २, सी = ३}

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


2

JEP 269 कलेक्शंस एपीआई के लिए कुछ सुविधा कारखाने के तरीके प्रदान करता है। यह फ़ैक्टरी विधियाँ वर्तमान जावा संस्करण में नहीं हैं, जो 8 है, लेकिन जावा 9 रिलीज़ के लिए योजना बनाई गई है।

के लिए Mapवहाँ दो कारखाने तरीके हैं: ofऔर ofEntries। का उपयोग करते हुए of, आप बारी-बारी से कुंजी / मूल्य जोड़े पास कर सकते हैं। उदाहरण के लिए, Mapजैसे बनाने के लिए {age: 27, major: cs}:

Map<String, Object> info = Map.of("age", 27, "major", "cs");

वर्तमान में इसके लिए दस ओवरलोड संस्करण हैं of, जिससे आप दस कुंजी / मान जोड़े वाले मानचित्र बना सकते हैं। यदि आपको यह सीमा या वैकल्पिक कुंजी / मान पसंद नहीं है, तो आप उपयोग कर सकते हैं ofEntries:

Map<String, Object> info = Map.ofEntries(
                Map.entry("age", 27),
                Map.entry("major", "cs")
);

दोनों ofऔर ofEntriesअपरिवर्तनीय वापस आ जाएगी Map, ताकि आप निर्माण के बाद उनके तत्व नहीं बदल सकते। आप JDK 9 अर्ली एक्सेस का उपयोग करके इन सुविधाओं को आज़मा सकते हैं ।


2

अच्छी तरह से ... मैं enums की तरह;)

enum MyEnum {
    ONE   (1, "one"),
    TWO   (2, "two"),
    THREE (3, "three");

    int value;
    String name;

    MyEnum(int value, String name) {
        this.value = value;
        this.name = name;
    }

    static final Map<Integer, String> MAP = Stream.of( values() )
            .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}

2

मैंने उत्तर पढ़ लिए हैं और मैंने अपना मैप बिल्डर को लिखने का फैसला किया है। बेझिझक कॉपी-पेस्ट करें और आनंद लें।

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

संपादित करें: हाल ही में, मैं सार्वजनिक स्थैतिक विधि को ofअक्सर ढूंढता रहता हूं और मुझे यह पसंद है। मैंने इसे कोड में जोड़ा और कंस्ट्रक्टर को निजी बना दिया, इस प्रकार स्थैतिक फैक्टरी विधि पैटर्न पर स्विच कर दिया।

EDIT2: हाल ही में, मुझे अब स्टैटिक विधि पसंद नहीं है, जिसे ofस्टैटिक आयात का उपयोग करते समय बहुत बुरा लगता है। मैंने mapOfइसके बजाय इसका नाम बदल दिया , जिससे यह स्थिर आयात के लिए अधिक उपयुक्त हो गया।

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