2011-11-30 10 views
32

मैं निम्नलिखित पैटर्न के बीमार हूँ:जावा map.get (कुंजी) - स्वचालित रूप से डालें (कुंजी) और अगर कुंजी मौजूद नहीं है तो वापस लौटें?

value = map.get(key); 
if (value == null) { 
    value = new Object(); 
    map.put(key, value); 
} 

यह उदाहरण केवल अतिरिक्त कोड की सतह खरोंच लिखे जाने की जब आप नक्शे नेस्ट है एक बहु-आयामी संरचना का प्रतिनिधित्व करने के लिए।

मुझे यकीन है कि इससे बचने के लिए कहीं कुछ मौजूद है, लेकिन मेरे गुगलिंग प्रयासों ने कुछ भी प्रासंगिक नहीं किया। कोई सुझाव?

+0

जिज्ञासा से, जिस वस्तु को आप रखना चाहते हैं, क्या यह सिर्फ एक वस्तु है, या प्रकार अलग-अलग होगा? साथ ही, क्या यह पहले से ही बनाया गया है या इसे केवल तभी बनाया जाना चाहिए जब कोई ऑब्जेक्ट पहले से मौजूद न हो? –

+0

इस प्रकार संकलन समय पर जाना जाता है। आम तौर पर यह एक स्ट्रिंग टू मैप (मानचित्र पर) * इंटीजर तक है। –

उत्तर

24

java.util.concurrent.ConcurrentMap 

और जावा 8

Java.util.Map 

से

putIfAbsent(K key, V value) 

जो कुंजी को मैप किया मान देता है या दिए गए मूल्य और अशक्त सम्मिलित करता है, तो कोई मूल्य नहीं है कुंजी के लिए मैप किया गया।

आप मूल्य के आलसी मूल्यांकन की जरूरत है वहाँ

computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) 
+3

रिटर्न: निर्दिष्ट कुंजी से जुड़े पिछले मान, या शून्य – user802421

+0

परफेक्ट के लिए कोई मैपिंग नहीं था, तो शून्य! यही वह है जिसे मैं ढूंढ रहा था। रोजर धन्यवाद। –

+5

ध्यान दें कि यह आपको एक नई वस्तु बनाने के लिए मजबूर करता है, भले ही मानचित्र में पहले से ही कोई उपलब्ध हो। यदि आप वास्तव में केवल 'नया ऑब्जेक्ट() 'बनाते हैं, तो यह नगण्य हो सकता है। –

3

इस पैटर्न के साथ समस्या यह है कि आप किसी भी तरह मूल्य उस मामले get() रिटर्न अशक्त में इस्तेमाल किया जाना चाहिए परिभाषित करने के लिए होगा है।

वहां निश्चित रूप से पुस्तकालय हैं और आईआईआरसी कुछ नए संग्रह भी हैं जो ऐसा करते हैं, लेकिन दुर्भाग्य से मुझे याद नहीं है कि वे कौन थे।

हालांकि, आप एक उपयोगिता विधि स्वयं लिख सकते हैं, बशर्ते आपके पास नए मान बनाने का एक मानक तरीका हो। कुछ इस तरह काम कर सकते हैं:

public static <K, V> V safeGet(K key, Map<K,V> map, Class<V> valueClass) throws /*add exceptions*/ { 
    V value = map.get(key); 
    if(value == null) { 
    value = valueClass.newInstance(); 
    map.put(key, value); 
    } 

    return value; 
} 

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

+0

द्वारा दिखाया गया है यह एक उपयोगी कोड स्निपेट है। धन्यवाद। मुझे नहीं पता था कि जेनेरिक के साथ इसे कैसे किया जाए। –

1

संपादित करें: ध्यान दें कि नीचे उल्लिखित सुविधा लंबे समय से बहिष्कृत है, और CacheBuilder इसके बजाय उपयोग किया जाना चाहिए।

अमरूद पुस्तकालय एक "कंप्यूटिंग नक्शा", MapMaker.makeComputingMap(Function) देखना है।

Map<String, Object> map = new MapMaker().makeComputingMap(
    new Function<String, Object>() { 
     public String apply(Stringt) { 
     return new Object(); 
     } 
    }); 

आप समारोह में कई बार जरूरत है, यह एक उपयोगिता वर्ग में निकालने, और उसके बाद इस तरह मानचित्र (जहां MyFunctions.NEW_OBJECT है स्थिर समारोह उदाहरण) बनाने के लिए:

Map<String, Object> map = new MapMaker() 
    .makeComputingMap(MyFunctions.NEW_OBJECT); 
+0

Google गुवा से 'मैपमेकर' मर चुका है। रेफरी: http://code.google.com/p/guava-libraries/wiki/MapMaker माइग्रेशन – kevinarpe

+0

मैं समझता हूं कि गुवा लोग सोचते हैं कि एक ऑटोकंप्यूटिंग 'Map.get()' खराब है, क्योंकि यह 'मानचित्र' अनुबंध को तोड़ देता है। यदि आप केवल आंतरिक रूप से कंप्यूटिंग मानचित्र का उपयोग करते हैं, तो इसके बजाय 'लोडिंग कैश' का उपयोग करना आसान होना चाहिए। मैं अप्रत्याशित कोड के साथ एक कंप्यूटिंग मानचित्र साझा करते समय होने वाली प्रतीक्षा में आपदा का एक बिंदु देख सकता हूं। उस उपयोग के मामले में, किसी को 'सुरक्षित गेट() 'उपयोगिता फ़ंक्शन का उपयोग करना चाहिए जैसे कि थॉमस द्वारा दिए गए उत्तर में। –

0

शायद मैं कर रहा हूँ पूरी समस्या को नहीं देख रहा है, लेकिन इस व्यवहार को मानचित्र ऑब्जेक्ट में जोड़ने के लिए विरासत या संरचना का उपयोग करने के बारे में कैसे?

+0

यह मुझे मिली सबसे अच्छी चीज़ थी, हां। उत्तर के लिए धन्यवाद। –

3

आप Eclipse Collections जो कुंजी को मैप किया मान देता है या दिए गए मूल्य सम्मिलित करता है और दिए गए मान देता है यदि कोई मूल्य नहीं कुंजी को मैप किया है से MutableMap और getIfAbsentPut() उपयोग कर सकते हैं।

आप एक विधि संदर्भ उपयोग कर सकते हैं एक नया Object बनाने के लिए:

MutableMap<String, Object> map = Maps.mutable.empty(); 
Object value = map.getIfAbsentPut("key", Object::new); 

या आप सीधे बना सकते हैं एक नया Object:

MutableMap<String, Object> map = Maps.mutable.empty();  
Object value = map.getIfAbsentPut("key", new Object()); 

पहले उदाहरण में, वस्तु बनाया जाएगा केवल तभी जब कुंजी पर मैप किए गए कोई मान नहीं है।

दूसरे उदाहरण में, ऑब्जेक्ट को बिना किसी पर बनाया जाएगा।

नोट: मैं ग्रहण संग्रह में योगदानकर्ता हूं।

16

जावा 8 के लिए अच्छा विधि कहते हैं Map: compute, computeIfPresent, computeIfAbsent

प्राप्त करने के लिए आप क्या जरूरत है:

Object existingOrCreated = map.computeIfAbsent(key, (k) -> new Object()); 
1

किसी भी मामले में आप अपने नक्शे अगर में एक डिफ़ॉल्ट डेटा प्राप्त करने की जरूरत है यह मौजूदा नहीं कर रहा है

map.getOrDefault(key, defaultValue); 

javadocs

+1

दिलचस्प है, लेकिन यह इसे मानचित्र में नहीं डालता क्योंकि ओपी ने पूछा –

संबंधित मुद्दे