HashMap के लिए बिल्डर


109

अमरूद हमें जावा प्रकारों के लिए महान कारखाने के तरीके प्रदान करता है, जैसे कि Maps.newHashMap()

लेकिन क्या जावा मैप्स के लिए बिल्डर भी हैं?

HashMap<String,Integer> m = Maps.BuildHashMap.
    put("a",1).
    put("b",2).
    build();

जवाबों:


20

चूंकि जावा 9 Mapइंटरफ़ेस में शामिल है:

  • Map.of(k1,v1, k2,v2, ..)
  • Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..)

उन कारखाने के तरीकों की सीमाएँ हैं:

  • nullकुंजी और / या मान के रूप में पकड़ नहीं कर सकते हैं (यदि आपको नल को संग्रहीत करने की आवश्यकता है, तो अन्य उत्तरों पर एक नज़र डालें)
  • उत्पादन अपरिवर्तनीय नक्शे

अगर हमें परस्पर मानचित्र (जैसे हाशप) की आवश्यकता है, तो हम इसके कॉपी-कंस्ट्रक्टर का उपयोग कर सकते हैं और इसके माध्यम से बनाए गए नक्शे की सामग्री की प्रतिलिपि बना सकते हैंMap.of(..)

Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );

2
ध्यान दें कि जावा 9 विधियां nullमूल्यों की अनुमति नहीं देती हैं, जो उपयोग के मामले के आधार पर एक समस्या हो सकती है।
प्रति लंडबर्ग

@JoshM। IMO Map.of(k1,v1, k2,v2, ...)का उपयोग तब सुरक्षित रूप से किया जा सकता है जब हमारे पास कई मूल्य नहीं होते हैं। मूल्यों की बड़ी मात्रा के लिए Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)हमें अधिक पठनीय कोड मिलता है जो कम त्रुटि वाला है (जब तक कि मैंने आपको गलत नहीं समझा)।
१०:४१ पर भजन १o ’

आप ठीक समझे। पूर्व वास्तव में मेरे लिए केवल सकल है; मैं इसे उपयोग करने से इनकार करता हूं!
जोश एम।

164

HashMaps के लिए ऐसी कोई बात नहीं है, लेकिन आप एक बिल्डर के साथ एक ImmutableMap बना सकते हैं:

final Map<String, Integer> m = ImmutableMap.<String, Integer>builder().
      put("a", 1).
      put("b", 2).
      build();

और अगर आपको एक परिवर्तनशील मानचित्र की आवश्यकता है, तो आप बस उसे HashMap निर्माता को खिला सकते हैं।

final Map<String, Integer> m = Maps.newHashMap(
    ImmutableMap.<String, Integer>builder().
        put("a", 1).
        put("b", 2).
        build());

43
ImmutableMapnullमूल्यों का समर्थन नहीं करता है। तो वहाँ इस दृष्टिकोण की सीमा है: यदि आप अपने में निर्धारित नहीं कर सकते मूल्यों HashMapको null
महत्वपूर्ण

5
शॉन- पेट्रिक-फ्लोयड , एक व्यावहारिक उदाहरण: स्प्रिंग का NamedParameterJdbcTemplate मानों के नाम को पैरामीटर नामों के हिसाब से परिभाषित करता है। मान लें कि मैं NullParameterJdbcTemplate का उपयोग करना चाहता हूं ताकि कॉलम मान शून्य करने के लिए सेट किया जा सके। मैं नहीं देखता: क) यह एक कोड गंध कैसे है; ख) यहाँ अशक्त वस्तु पैटर्न का उपयोग कैसे किया जाता है
महत्वपूर्ण

2
@vitaly उस पर बहस नहीं कर सकती
सीन पैट्रिक फ्लॉयड

2
क्या new HashMapस्थैतिक Maps.newHashMapविधि के बजाय जावा कंस्ट्रक्टर का उपयोग करने में कुछ गड़बड़ है ?
कोरेथन

1
@CorayThan - जोनिक सही है, यह केवल स्थैतिक प्रकार के अनुमान पर निर्भर एक शॉर्टकट है। stackoverflow.com/a/13153812
एंडर्सडजोनसन

46

काफी बिल्डर नहीं है, लेकिन एक शुरुआती का उपयोग कर:

Map<String, String> map = new HashMap<String, String>() {{
    put("a", "1");
    put("b", "2");
}};

रुको। क्या यह map instanceof HashMapगलत नहीं होगा ? एक महान विचार नहीं लगता है।
एलजार लीबोविच

3
@ एलाज़र map.getClass()==HashMap.classझूठे लौटेगा लेकिन यह एक बेवकूफ परीक्षण है। HashMap.class.isInstance(map)पसंद किया जाना चाहिए, और यह सच हो जाएगा।
सीन पैट्रिक फ्लोयड

59
उस ने कहा: मुझे अभी भी लगता है कि यह समाधान बुराई है।
सीन पैट्रिक फ्लोयड

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

14
यह एक बहुत बुरा समाधान है और इससे बचना चाहिए: stackoverflow.com/a/27521360/3253277
अलेक्जेंड्रे ड्यूब्रिल

36

यह स्वीकृत उत्तर के समान है, लेकिन मेरे विचार में थोड़ा साफ है:

ImmutableMap.of("key1", val1, "key2", val2, "key3", val3);

उपरोक्त विधि के कई रूप हैं, और वे स्थिर, अपरिवर्तनीय, अपरिवर्तनीय मानचित्र बनाने के लिए महान हैं।


4
मैंने एक बिल्डर के लिए कहा। आप मुट्ठी भर तत्वों तक सीमित हैं।
एलज़ार लीबोविच

अच्छा और साफ है, लेकिन यह मुझे पर्ल के संचालक के लिए लंबे समय तक बना देता है ... जो एक अजीब लग रहा है।
हारून मेंपा

10

यहाँ एक बहुत ही सरल है ...

public class FluentHashMap<K, V> extends java.util.HashMap<K, V> {
  public FluentHashMap<K, V> with(K key, V value) {
    put(key, value);
    return this;
  }

  public static <K, V> FluentHashMap<K, V> map(K key, V value) {
    return new FluentHashMap<K, V>().with(key, value);
  }
}

फिर

import static FluentHashMap.map;

HashMap<String, Integer> m = map("a", 1).with("b", 2);

Https://gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065 देखें


मुझे आपके दृष्टिकोण की सरलता पसंद है। विशेष रूप से 2017 के बाद से (लगभग 2018 अब!), और JDK में अभी भी ऐसी कोई एपीआई नहीं है
मिलाद नासरी

बहुत अच्छा लग रहा है, धन्यवाद। @MadadNaseri यह समझ में आता है कि JDK के पास अभी भी अपने एपीआई में ऐसा कुछ नहीं है, जो एक शर्मनाक बात है।
असंभव

9

एक साधारण नक्शा बिल्डर लिखने के लिए तुच्छ है:

public class Maps {

    public static <Q,W> MapWrapper<Q,W> map(Q q, W w) {
        return new MapWrapper<Q, W>(q, w);
    }

    public static final class MapWrapper<Q,W> {
        private final HashMap<Q,W> map;
        public MapWrapper(Q q, W w) {
            map = new HashMap<Q, W>();
            map.put(q, w);
        }
        public MapWrapper<Q,W> map(Q q, W w) {
            map.put(q, w);
            return this;
        }
        public Map<Q,W> getMap() {
            return map;
        }
    }

    public static void main(String[] args) {
        Map<String, Integer> map = Maps.map("one", 1).map("two", 2).map("three", 3).getMap();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

6

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

HashMap<String,Integer> m = Maps.newHashMap(
    ImmutableMap.of("a",1,"b",2)
);

यह उत्तम दर्जे का और पठनीय नहीं है, लेकिन यह काम करता है।


1
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);, बेहतर है?
lschin

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

4

HashMapपारस्परिक है; बिल्डर की कोई आवश्यकता नहीं है।

Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);

यदि आप इसके साथ किसी क्षेत्र को शुरू करना चाहते हैं तो क्या होगा? एक ही पंक्ति में सभी तर्क क्षेत्र और c'tor के बीच बिखरे हुए तर्क से बेहतर है।
एलाजार लीबोविच

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

1
एर, ImmutableMapवहाँ स्पष्ट रूप से कहा जाना चाहिए था ।
कॉलिनड सिप Col

मुझे ऐसा नहीं लगता। मैं बल्कि एक ही पंक्ति में परिभाषा में intialization देखना चाहते हैं, तो उन्हें एक गैर स्थैतिक intialization {{init();}}(निर्माता में नहीं, क्योंकि अन्य निर्माता इसे भूल सकता है) में tucked । और यह अच्छा है कि यह परमाणु कार्रवाई की तरह है। यदि नक्शा अस्थिर है, तो एक बिल्डर के साथ यह सुनिश्चित करना कि यह हमेशा या तो nullअंतिम स्थिति में है, कभी भी आधा भरा नहीं है।
एलाजार लीबोविच सेप

1

आप ग्रहण संग्रह में धाराप्रवाह एपीआई का उपयोग कर सकते हैं :

Map<String, Integer> map = Maps.mutable.<String, Integer>empty()
        .withKeyValue("a", 1)
        .withKeyValue("b", 2);

Assert.assertEquals(Maps.mutable.with("a", 1, "b", 2), map);

यहाँ एक और अधिक विस्तार और उदाहरण के साथ ब्लॉग है

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


0

मुझे कुछ समय पहले भी इसी तरह की आवश्यकता थी। इसका अमरूद से कोई लेना-देना नहीं है, लेकिन आप Mapधाराप्रवाह बिल्डर का उपयोग करके साफ-सफाई करने में सक्षम होने के लिए कुछ ऐसा कर सकते हैं ।

एक बेस क्लास बनाएं जो मैप का विस्तार करता है।

public class FluentHashMap<K, V> extends LinkedHashMap<K, V> {
    private static final long serialVersionUID = 4857340227048063855L;

    public FluentHashMap() {}

    public FluentHashMap<K, V> delete(Object key) {
        this.remove(key);
        return this;
    }
}

फिर अपनी आवश्यकताओं के अनुरूप विधियों के साथ धाराप्रवाह निर्माता बनाएँ:

public class ValueMap extends FluentHashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    public ValueMap() {}

    public ValueMap withValue(String key, String val) {
        super.put(key, val);
        return this;
    }

... Add withXYZ to suit...

}

फिर आप इसे इस तरह लागू कर सकते हैं:

ValueMap map = new ValueMap()
      .withValue("key 1", "value 1")
      .withValue("key 2", "value 2")
      .withValue("key 3", "value 3")

0

यह एक ऐसी चीज है जिसे मैं हमेशा से चाहता था, खासकर टेस्ट फिक्स्चर सेट करते समय। अंत में, मैंने खुद का एक सरल धाराप्रवाह बिल्डर लिखने का फैसला किया जो किसी भी मानचित्र कार्यान्वयन का निर्माण कर सकता है - https://gist.github.com/samshu/b471f5a2925fa9d9b718795d8bbdfd42#file-mapbuilder-java

    /**
     * @param mapClass Any {@link Map} implementation type. e.g., HashMap.class
     */
    public static <K, V> MapBuilder<K, V> builder(@SuppressWarnings("rawtypes") Class<? extends Map> mapClass)
            throws InstantiationException,
            IllegalAccessException {
        return new MapBuilder<K, V>(mapClass);
    }

    public MapBuilder<K, V> put(K key, V value) {
        map.put(key, value);
        return this;
    }

    public Map<K, V> build() {
        return map;
    }

0

यहाँ एक मैंने लिखा है

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

public class MapBuilder<K, V> {

    private final Map<K, V> map;

    /**
     * Create a HashMap builder
     */
    public MapBuilder() {
        map = new HashMap<>();
    }

    /**
     * Create a HashMap builder
     * @param initialCapacity
     */
    public MapBuilder(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    /**
     * Create a Map builder
     * @param mapFactory
     */
    public MapBuilder(Supplier<Map<K, V>> mapFactory) {
        map = mapFactory.get();
    }

    public MapBuilder<K, V> put(K key, V value) {
        map.put(key, value);
        return this;
    }

    public Map<K, V> build() {
        return map;
    }

    /**
     * Returns an unmodifiable Map. Strictly speaking, the Map is not immutable because any code with a reference to
     * the builder could mutate it.
     *
     * @return
     */
    public Map<K, V> buildUnmodifiable() {
        return Collections.unmodifiableMap(map);
    }
}

आप इसे इस तरह उपयोग करते हैं:

Map<String, Object> map = new MapBuilder<String, Object>(LinkedHashMap::new)
    .put("event_type", newEvent.getType())
    .put("app_package_name", newEvent.getPackageName())
    .put("activity", newEvent.getActivity())
    .build();

0

जावा 8 का उपयोग करना:

यह जावा -9 का एक दृष्टिकोण है Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)

public class MapUtil {
    import static java.util.stream.Collectors.toMap;

    import java.util.AbstractMap.SimpleEntry;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.stream.Stream;

    private MapUtil() {}

    @SafeVarargs
    public static Map<String, Object> ofEntries(SimpleEntry<String, Object>... values) {
        return Stream.of(values).collect(toMap(Entry::getKey, Entry::getValue));
    }

    public static SimpleEntry<String, Object> entry(String key, Object value) {
        return new SimpleEntry<String, Object>(key, value);
    }
}

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

import static your.package.name.MapUtil.*;

import java.util.Map;

Map<String, Object> map = ofEntries(
        entry("id", 1),
        entry("description", "xyz"),
        entry("value", 1.05),
        entry("enable", true)
    );


0

अंडरस्कोर-जावा, हैशमैप का निर्माण कर सकता है।

Map<String, Object> value = U.objectBuilder()
        .add("firstName", "John")
        .add("lastName", "Smith")
        .add("age", 25)
        .add("address", U.arrayBuilder()
            .add(U.objectBuilder()
                .add("streetAddress", "21 2nd Street")
                .add("city", "New York")
                .add("state", "NY")
                .add("postalCode", "10021")))
        .add("phoneNumber", U.arrayBuilder()
            .add(U.objectBuilder()
                .add("type", "home")
                .add("number", "212 555-1234"))
            .add(U.objectBuilder()
                .add("type", "fax")
                .add("number", "646 555-4567")))
        .build();
    // {firstName=John, lastName=Smith, age=25, address=[{streetAddress=21 2nd Street,
    // city=New York, state=NY, postalCode=10021}], phoneNumber=[{type=home, number=212 555-1234},
    // {type=fax, number=646 555-4567}]}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.