2013-02-14 12 views
7

मैं एक जवाब here जहां कोड ConcurrentMap की putIfAbsent पद्धति के उपयोग का प्रदर्शन पढ़ तैनात मानचित्र करें कि इसका उपयोग किया जाएगा या नहीं। यदि वस्तु भारी है तो इसका महत्वपूर्ण प्रभाव हो सकता है।lambdas और putIfAbsent

यह मेरे लिए हुआ कि यह Lambdas का उपयोग करने का अवसर होगा। मैंने जावा 8 डाउनलोड नहीं किया है, क्या मैं आधिकारिक (कंपनी नीति) तक पहुंचने में सक्षम हूं, इसलिए मैं इसका परीक्षण नहीं कर सकता लेकिन क्या ऐसा कुछ वैध और प्रभावी होगा?

public long addTo(String key, long value) { 
    return map.putIfAbsent(key,() -> new AtomicLong(0)).addAndGet(value); 
} 

मैं new AtomicLong(0) के मूल्यांकन में देरी करने के लिए जब तक यह वास्तव में निर्धारित किया जाता है कि यह है क्योंकि यह मानचित्र में मौजूद नहीं है बनाया जाना चाहिए लैम्ब्डा उपयोग करने के लिए उम्मीद कर रहा हूँ।

जैसा कि आप देख सकते हैं कि यह अधिक संक्षिप्त और कार्यात्मक है।

अनिवार्य रूप से मुझे लगता है कि मेरे सवालों हैं:

  1. क्या यह काम करता है?
  2. या मैंने पूरी तरह से लैम्बडास का गलत व्याख्या किया है?
  3. एक दिन इस काम की तरह कुछ हो सकता है?
+2

आप जावा 8 डाउनलोड करने और इसे स्वयं परीक्षण करने में सक्षम नहीं हैं? क्या आपकी कंपनी आपको अपने काम कंप्यूटर पर कुछ भी स्थापित करने से रोकती है (मूल्यांकन उद्देश्यों के लिए भी)? फिर अपने व्यक्तिगत व्यक्ति पर कोशिश करने के बारे में कैसे? –

+0

@ सिमोनलेहमान - बीटीडब्लू - आपकी टिप्पणी के बाद मैंने जावा 8 स्थापित किया और न केवल इसमें लैम्ब्डास था (एक अतिरिक्त मुझे स्थापित करना था, लेकिन इसके आसपास नहीं मिला) लेकिन डीबीविज़ुअलर ने काम करना बंद कर दिया - इसलिए मैंने इसे हटा दिया। माफ़ कीजिये। शायद अगले साल। – OldCurmudgeon

उत्तर

6

अद्यतन 2015-08-01

computeIfAbsent पद्धति के रूप में नीचे वर्णित वास्तव में added to Java SE 8 किया गया है। अर्थशास्त्र पूर्व-रिलीज संस्करण के बहुत करीब प्रतीत होता है।

इसके अतिरिक्त, computeIfAbsent, नए डिफ़ॉल्ट तरीकों के पूरे ढेर के साथ, Map इंटरफ़ेस में जोड़ा गया है। बेशक, सामान्य रूप से नक्शे परमाणु अद्यतनों का समर्थन नहीं कर सकते हैं, लेकिन नई विधियां एपीआई के लिए काफी सुविधा प्रदान करती हैं।


तुम क्या करने की कोशिश कर रहे क्या काफी उचित है, लेकिन दुर्भाग्य से यह ConcurrentMap के वर्तमान संस्करण के साथ काम नहीं करता। हालांकि, एक वृद्धि रास्ते पर है। समवर्ती पुस्तकालय के नए संस्करण में ConcurrentHashMapV8 शामिल है जिसमें एक नई विधि computeIfAbsent शामिल है। यह बहुत कुछ आपको वही करने की अनुमति देता है जो आप करना चाहते हैं। इस प्रकार इस नई विधि का उपयोग करना, अपने उदाहरण फिर से लिखा जा सकता है:

public long addTo(String key, long value) { 
    return map.computeIfAbsent(key,() -> new AtomicLong(0)).addAndGet(value); 
} 

ConcurrentHashMapV8 के बारे में अधिक जानकारी के लिए, डौग Lea के initial announcement thread संगामिति ब्याज मेलिंग सूची पर देखते हैं। धागे के नीचे कई संदेश a followup message है जो एक उदाहरण दिखाता है जो आप करने की कोशिश कर रहे हैं। (नोट हालांकि पुराने लैम्ब्डा वाक्यविन्यास। यह संदेश अगस्त 2011 से सभी के बाद था।) और ConcurrentHashMapV8 के लिए recent javadoc है।

यह काम जावा 8 में एकीकृत करने का इरादा है, लेकिन यह अभी तक जहां तक ​​मैं देख सकता हूं। साथ ही, यह अभी भी प्रगति पर एक काम है, नाम और चश्मा बदल सकते हैं, आदि

+0

धन्यवाद - इस तथ्य को छोड़कर कि इसे 'ConcurrentHashMapV8' कहा जा रहा है। क्या एक भयावह विचार !! – OldCurmudgeon

+1

मुझे यकीन नहीं है कि यह अभी भी जावा 8 में एकीकृत होने के समय सीएचएमवी 8 कहलाए जा रहा है। मुझे संदेह है कि डौग ली ने इसे सीएचएमवी 8 कहा है, इसलिए इसे सीएएम के रूप में इस्तेमाल किया जा सकता है जैसे कि ऐप्स, टेस्ट, तुलना के लिए बेंचमार्क प्रयोजनों। ली का कहना है कि इसका उद्देश्य सीएचएम के प्रतिस्थापन होना है। –

+0

यह अच्छी खबर है। विस्तार के लिए धन्यवाद। – OldCurmudgeon

2

दुर्भाग्य से यह उतना आसान नहीं है। आपके द्वारा स्केच किए गए दृष्टिकोण के साथ दो मुख्य समस्याएं हैं: 1. मानचित्र के प्रकार को Map<String, AtomicLong> से Map<String, AtomicLongFunction> में बदलना होगा (जहां AtomicLongFunction कुछ फ़ंक्शन इंटरफ़ेस है जिसमें एक ही विधि है जिसमें कोई तर्क नहीं होता है और AtomicLong देता है)। 2. जब आप मानचित्र से तत्व पुनर्प्राप्त करते हैं तो आपको AtomicLong प्राप्त करने के लिए प्रत्येक बार फ़ंक्शन को लागू करने की आवश्यकता होगी। इसके परिणामस्वरूप प्रत्येक बार जब आप इसे पुनर्प्राप्त करेंगे तो एक नया उदाहरण तैयार होगा, जो संभवतः आप जो चाहते थे उसकी संभावना नहीं है।

लापता मूल्यों को भरने की मांग पर एक फ़ंक्शन चलाने वाला नक्शा रखने का विचार एक अच्छा है, और वास्तव में Google की गुवा पुस्तकालय में एक नक्शा है जो ठीक है; उनके MapMaker देखें। वास्तव में है कि कोड जावा 8 लैम्ब्डा भाव से लाभ होगा: के बजाय

ConcurrentMap<Key, Graph> graphs = new MapMaker() 
     .concurrencyLevel(4) 
     .weakKeys() 
     .makeComputingMap(
      new Function<Key, Graph>() { 
      public Graph apply(Key key) { 
       return createExpensiveGraph(key); 
      } 
      }); 

आप

ConcurrentMap<Key, Graph> graphs = new MapMaker() 
     .concurrencyLevel(4) 
     .weakKeys() 
     .makeComputingMap((Key key) -> createExpensiveGraph(key)); 

या

ConcurrentMap<Key, Graph> graphs = new MapMaker() 
     .concurrencyLevel(4) 
     .weakKeys() 
     .makeComputingMap(this::createExpensiveGraph); 
+0

किसी भी तरह से मुझे पता था कि मेरा समाधान इतना आसान था कि यह खत्म हो जाएगा। तो मैं लैम्ब्डा के ** परिणाम ** की बजाय मानचित्र में ** लैम्ब्डा ** को प्रभावी ढंग से जोड़ रहा हूं ... ओह ठीक है। – OldCurmudgeon

2

AtomicLong लिखने में सक्षम हो जाएगा वास्तव में एक भारी वस्तु नहीं है । भारी वस्तुओं के लिए मैं आलसी प्रॉक्सी पर विचार करता हूं और आवश्यकता होने पर ऑब्जेक्ट बनाने के लिए उसमें एक लैम्ब्डा प्रदान करता हूं।

class MyObject{ 
    void doSomething(){} 
} 

class MyLazyObject extends MyObject{ 
    Funktion create; 
    MyLazyObject(Funktion create){ 
     this.create = create; 
    } 
    MyObject instance; 
    MyObject getInstance(){ 
     if(instance == null) 
      instance = create.apply(); 
     return instance; 
    } 
    @Override void doSomething(){getInstance().doSomething();} 
} 

public long addTo(String key, long value) { 
    return map.putIfAbsent(key, new MyLazyObject(() -> new MyObject(0))); 
} 
+0

मैंने एक 'एटमिक लोंग' का इस्तेमाल एक उदाहरण स्थान धारक के रूप में किया था, मैं वास्तव में बहुत भारी वस्तुओं के संदर्भ में सोच रहा था। यह प्रभावी दिखता है लेकिन आलसी को लागू करने के लिए बहुत सारी चीजें चल रही हैं जो किसी भी तरह से लैम्ब्डा में सहज रहती हैं। – OldCurmudgeon

+0

गुवा पुस्तकालय का उपयोग करना आसान लगता है। लेकिन आलसी वस्तुओं को लिखना आपको स्वतंत्र रूप से मानचित्र कार्यान्वयन बनाता है। आप एक सामान्य InvocationHandler भी बना सकते हैं जो सभी विधि आमंत्रणों को प्रतिनिधि करेगा, [प्रॉक्सी] (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html) देखें। लेकिन आप सही हैं, यह ज्यादातर मामलों में एक वास्तविक ओवरकिल होगा। –

1

ध्यान दें कि जावा 8 ConcurrentHashMap का उपयोग करके यह AtomicLong मानों के लिए पूरी तरह से अनावश्यक है। आप सुरक्षित रूप से ConcurrentHashMap.merge उपयोग कर सकते हैं:

ConcurrentMap<String, Long> map = new ConcurrentHashMap<String, Long>(); 

public long addTo(String key, long value) { 
    return map.merge(key, value, Long::sum); 
} 

यह बहुत आसान है और यह भी काफी तेजी।

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