java - मैं एक स्थिर मानचित्र कैसे शुरू कर सकता हूं?




dictionary collections (20)

जावा में एक स्थिर मानचित्र कैसे शुरू करेंगे?

विधि एक: स्थिर प्रारंभिक
विधि दो: उदाहरण प्रारंभकर्ता (अज्ञात उपclass) या कुछ अन्य विधि?

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

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

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

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

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

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

        Map<String,Object> myMap = hashMap(
                bob -> 5,
                TheGimp -> 8,
                incredibleKoolAid -> "James Taylor",
                heyArnold -> new Date()
        );

        Map<String,Integer> typesafeMap = treeMap(
                a -> 5,
                bee -> 8,
                sea -> 13
                deep -> 21
        );

https://gist.github.com/galdosd/10823529 पर अनचाहे नमूना कोड इस पर दूसरों की राय पर उत्सुक होगा (यह हल्का बुरा है ...)


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

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

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

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

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);
    }
}

खैर ... मुझे 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 ) );
}

जावा 5 यह अधिक कॉम्पैक्ट वाक्यविन्यास प्रदान करता है:

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

जावा 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));

यह सबसे ज्यादा terse और थोड़ा चौराहे नहीं है, लेकिन

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

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


दूसरी विधि का एक फायदा यह है कि आप इसे संग्रहित करने के लिए संग्रह .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!

मुझे अज्ञात वर्ग वाक्यविन्यास पसंद है; यह सिर्फ कम कोड है। हालांकि, मैंने पाया है कि एक प्रमुख con यह है कि आप उस वस्तु को रिमोटिंग के माध्यम से क्रमबद्ध करने में सक्षम नहीं होंगे। आपको रिमोट साइड पर अज्ञात वर्ग नहीं ढूंढने के बारे में अपवाद मिलेगा।


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

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

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

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

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

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

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

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

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

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

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

पहली युक्ति

पहली युक्ति यह है कि आप मानचित्र के लिए स्थानीय संदर्भ बना सकते हैं और आप इसे लघु नाम देते हैं:

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 तत्व जोड़ myMap2 । इसे पुनः उपयोग करने योग्य बनाने के लिए, हम मानचित्र को स्वयं को सहायक विधि का पैरामीटर बना सकते हैं, लेकिन फिर प्रारंभिक कोड कोई छोटा नहीं होगा।

तीसरी नोक

तीसरी नोक यह है कि आप पॉपुलटिंग कार्यक्षमता के साथ पुनः उपयोग करने योग्य बिल्डर-जैसी सहायक वर्ग बना सकते हैं। यह वास्तव में एक साधारण, 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
    }
}

मैं दृढ़ता से स्थिर ब्लॉक शैली पर "डबल ब्रेस प्रारंभिकरण" शैली का सुझाव दे सकता हूं।

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

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

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

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

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


मैंने कुछ अलग किया है। सबसे अच्छा नहीं, लेकिन यह मेरे लिए काम करता है। शायद यह "जेनेरिक" हो सकता है।

private static final Object[][] ENTRIES =
{
  {new Integer(1), "one"},
  {new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);

private static Map newMap(Object[][] entries)
{
  Map map = new HashMap();

  for (int x = 0; x < entries.length; x++)
  {
    Object[] entry = entries[x];

    map.put(entry[0], entry[1]);
  }

  return map;
}

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

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);
        }
    }
}

यहां जावा 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]));

ल्यूक द्वारा प्रस्तावित एक answer जो जावा 8 का उपयोग करके मानचित्र शुरू करता है लेकिन आईएमएचओ यह बदसूरत और पढ़ने में मुश्किल लगता है। हम नक्शा प्रविष्टियों का एक स्ट्रीम बना सकते हैं। हमारे पास पहले से java.util.AbstractMap में Entry दो कार्यान्वयन हैं जो 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));

जावा 9 के लिए हम यहां Map.of उपयोग भी कर सकते हैं जैसा कि Map.of द्वारा उनके उत्तर में दिया गया here ।


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

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

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

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

Map लिए दो कारखाने के तरीके हैं: 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")
);

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


ग्रहण संग्रह (पूर्व में जीएस संग्रह ) के साथ, निम्नलिखित सभी काम करेंगे:

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");
} 

नोट: मैं ग्रहण संग्रह के लिए एक कमिटर हूं








idiomatic