2017-08-02 41 views
11

Java8 उन अच्छा तरीकों getOrDefault() और putIfAbsent() शुरू की, की तरह कोड लिखने के लिए अनुमति:क्या मुझे getOrDefault() का उपयोग करने के बाद put() या putIfAbsent() का उपयोग करना चाहिए?

Map<Foo, List<Bar>> itemsByFoo = ... 
List<Bar> bars = itemsByFoo.getOrDefault(key, new ArrayList<>()); 
bars.add(someNewBar); 

अब मैं सोच रहा हूँ अगर वहाँ या तो के लिए अच्छा तथ्यात्मक कारण हैं कार्य करें:

itemsByFoo.put(key, bars); 

या

itemsByFoo.putIfAbsent(key, bars); 

दोनों काम करेगा:

  • विकल्प 1 अनावश्यक का एक बहुत कुछ कर कॉल "डाल" जब सूचियों करने के लिए जोड़ने तत्वों अक्सर ऐसा होता है
  • OPTION2 अनावश्यक "containsKey" का एक बहुत कुछ कर भी सकती है और कहता है जब नई चाबी के लिए नई प्रविष्टियां जोड़ने प्रमुख है

SO: विकल्प 1 या विकल्प 2 "हमेशा" के लिए जाने के अच्छे कारण हैं? आप नक्शे को संशोधित करने के बिना एक अनुपस्थित मूल्य के लिए एक स्टैंड में उपयोग करना चाहते हैं

+13

अहम, * न *। 'आइटम्स ByFoo.computeIfAbsent (कुंजी, एक्स -> नया ऐरेलिस्ट <>()) .add (someNewBar) का उपयोग करें;' पूरे ऑपरेशन के लिए। – Holger

+0

@ होल्गर हाँ :) उत्कृष्ट बिंदु। चूंकि 'putIfAbsent' एक' शून्य 'वापस कर सकता है क्योंकि यह * पिछले * मान देता है ... इसके अलावा' computeifAbsent' जावा -8 में मौजूद है, 7 नहीं। मुझे इससे पहले सामना करना पड़ा है ... – Eugene

+2

@Eugene: 'putIfAbsent' को जावा 8 में' मानचित्र 'इंटरफ़ेस में जोड़ा गया था, क्योंकि अब यह' डिफ़ॉल्ट 'विधियों के साथ संभव था, लेकिन इसे' ConcurrentMap.putIfAbsent' का अनुबंध रखना था, जो जावा 5 के बाद से मौजूद है, इसलिए यह 'computeIfAbsent' के रूप में सुविधाजनक नहीं है ... – Holger

उत्तर

19

getOrDefault उपयुक्त है। यदि आप अनुपस्थित कुंजी के लिए एक नया मान जोड़ना चाहते हैं, तो आप इसे एक ऑपरेशन में कर सकते हैं।

List<Bar> bars = itemsByFoo.computeIfAbsent(key, x -> new ArrayList<>()); 
bars.add(someNewBar); 

या यहाँ तक कि

itemsByFoo.computeIfAbsent(key, x -> new ArrayList<>()).add(someNewBar); 

सबसे अच्छा मामले में, जब HashMap साथ की तरह, Map कार्यान्वयन द्वारा ओवरराइड जा रहा है, यह एक एकल हैश देखने केवल उठाना पड़ेगा।

putIfAbsentdefault कार्यान्वयन का उपयोग करते समय केवल दो लुकअप भालू है, लेकिन, ज़ाहिर है, Map कार्यान्वयन इसके लिए एक एकल लुकअप कार्यान्वयन प्रदान करेगा। फिर भी, getOrDefault और putIfAbsent के संयोजन अभी भी सबसे अच्छा मामले में दो लुकअप सहन होता है, जबकि एक अनुकूलित computeIfAbsent केवल एक ही है।

+0

नामक किसी भी मामले में 'itemFoo.compute ... नहीं है; bars.add (someNewBar) 'अब दौड़ की स्थिति? चूंकि यह एक परमाणु ऑपरेशन नहीं है; जब कोई 'add' किया जाता है तब तक कोई उस प्रविष्टि को हटा सकता है? मुझे आश्चर्य है कि क्या मैं आज निम्नलिखित प्रश्नों के साथ आपकी धैर्य सीमा को मार रहा हूं ... – Eugene

+5

@ यूजीन: यह एक सामान्य 'मानचित्र' प्रश्न है। परमाणु होने की आवश्यकता नहीं थी। अन्यथा, आपके पास करने के लिए बहुत कुछ है। जबकि आप सम्मिलन थ्रेड को 'गणना' के अंदर सबकुछ सुरक्षित कर सकते हैं, तब तक उस कोड से कोई संबंध नहीं है जो अंततः 'सूची' पढ़ता है और यदि कोड स्वयं में समाप्त नहीं होता है, तो उसे कोड पढ़ना होगा, इसलिए किसी भी वास्तविक जीवन के मामले के लिए, वैसे भी अतिरिक्त प्रयास की आवश्यकता होगी। – Holger

+0

धन्यवाद। दुनिया में जहां मैं यहां 'सीएचएम' देखता हूं? मेरी गलती। यह 'putIfAbsent' के बारे में इतना अच्छा बिंदु है जो डिफ़ॉल्ट कार्यान्वयन में 2 लुक-अप करता है ... मैंने अभी यह देखा है कि यह' get' 'तो 'put' करता है। यह एक शानदार उदाहरण देगा कि डिफ़ॉल्ट विधियों को ओवरराइड क्यों किया जाता है। – Eugene

5

computeIfAbsent बारे में महत्वपूर्ण बिंदु है कि यह एक Function जो केवल तभी Key अनुपस्थित है निष्पादित हो जाएगा लगता है और हम एक डिफ़ॉल्ट Value की जरूरत है।

जबकि getOrDefault को डिफ़ॉल्ट Value स्वयं की गणना की आवश्यकता है, पहले ही गणना की गई है। इस मामले में, डिफ़ॉल्ट Value हम की आवश्यकता होगी एक new ArrayList<Bar>(), जो ढेर पर एक नई वस्तु के आवंटन की पक्ष प्रभाव है।

हम यह सुनिश्चित करना चाहते हैं कि जब तक हम सुनिश्चित न हों कि keyitemsByFoo में पहले से नहीं है। अन्यथा हम एकत्र करने के लिए gc के लिए अनावश्यक कचरा उत्पन्न करेंगे।

+0

उत्कृष्ट अतिरिक्त जानकारी ;-) – GhostCat

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