2016-07-20 22 views
8

से मैं जावा 8 में एक लैम्ब्डा समारोह बनाने के लिए, यह classname है और फिर बाद में अपनी classname से फिर से समारोह का दृष्टांत प्राप्त करना चाहते हैं।का दृष्टांत जावा लैम्ब्डा समारोह नाम

यह है कि मैं क्या करने की कोशिश है:

Exception in thread "main" java.lang.ClassNotFoundException: mypackage.SimpleLambda$$Lambda$1/471910020 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:264) 
    at mypackage.SimpleLambda.main(SimpleLambda.java:12) 
:

import java.util.function.Consumer; 

public class SimpleLambda 
{ 
    public static void call(String aLambdaClassName, String aArg) throws Exception 
    { 
     Class<Consumer<String>> lClass = (Class<Consumer<String>>) Class.forName(aLambdaClassName); 
     Consumer<String> newlamba = lClass.newInstance(); 
     newlamba.accept(aArg); 
    } 

    public static void main(String[] args) throws Exception 
    { 
     { 
      // Attempt with a static method as lambda 
      Consumer<String> lambda = Host::action; 
      String classname = lambda.getClass().getName(); 
      call(classname, "Hello world"); 
     } 

     { 
      // Attempt with a locally defined lambda 
      Consumer<String> lambda = (s) -> { System.out.println(s); }; 
      String classname = lambda.getClass().getName(); 
      call(classname, "Hello world"); 
     } 
    } 
} 

class Host { 
    public static void action(String aMessage) { 
     System.out.println(aMessage); 
    } 
} 

हालांकि, इस कोड के साथ (दोनों वेरिएंट में, स्थैतिक विधि संदर्भ का उपयोग करते हुए और स्थानीय स्तर पर घोषित लैम्ब्डा का प्रयोग करके), मैं एक अपवाद मिल

मुझे उम्मीद थी कि मैं कम से कम स्थिर विधि संदर्भ को फिर से चालू कर सकता हूं ... नहीं, स्पष्ट रूप से नहीं।

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

+2

आप उनके साथ क्या करने की कोशिश कर रहे हैं? Lambdas तत्काल नहीं हैं, वे सिर्फ * हैं *। – 4castle

+0

अनिवार्य रूप से, मैं एक लैम्ब्डा को एक स्थिर आंतरिक कक्षा की तरह एक समारोह के साथ इलाज करना चाहता हूं। मैं इसे प्रति वर्ग के नाम से पास करना चाहता हूं क्योंकि मुझे इसे एपीआई के माध्यम से पास करने की आवश्यकता है जो केवल स्ट्रिंग पैरामीटर स्वीकार करता है।तो एक बार जब मैं एपीआई के अंदर नाम प्राप्त करता हूं, तो मैं फिर से अपने क्लासनाम से लैम्ब्डा को फिर से बनाना चाहता हूं ताकि मैं इसे कॉल कर सकूं। अजीब लगता है? हाँ, यह है ... लेकिन जैसा कि मैंने कहा: यह ग्रोवी में किया और अच्छी तरह से काम करता है। मुझे एहसास है कि यह जावा में काम नहीं करेगा, लेकिन अगर किसी के पास यह संकेत है कि यह कैसे करना है, तो वास्तव में अच्छा होगा। – rec

+0

मैंने उपयोग को और स्पष्ट करने के लिए उदाहरण अपडेट किया। – rec

उत्तर

5

खैर, यह Oracle की JRE/OpenJDK "गुमनाम वर्गों" का उपयोग करने, जिस पर सभी नाम से पहुँचा नहीं जा सकता का एक विशेष गुण है। लेकिन फिर भी इस के बिना, कोई कारण नहीं है कि यह काम करना चाहिए है:

  • Class.forName(String) की कोशिश करता फोन करने वाले का ClassLoader के माध्यम से वर्ग को हल करने। इसलिए यदि सामान्य वर्गों का उपयोग करके लैम्ब्डा अभिव्यक्तियों को कार्यान्वित किया गया था, तो अलग-अलग ClassLoader
  • Class.newInstance() के माध्यम से लोड होने पर भी पहुंच योग्य नहीं था, यदि public नो-Arg कन्स्ट्रक्टर है तो केवल तभी काम करता है। आप कल्पना नहीं कर सकते एक नहीं आर्ग निर्माता है कि वहाँ है और न ही यह public
  • धारणा पूरे समारोह के तर्क रहते हैं में एक भी वर्ग गलत है है है। एक काउंटर उदाहरण java.lang.reflect.Proxy होगा जो InvocationHandler पर लागू कार्यान्वयन को उत्पन्न करता है। अपने वर्ग नाम के माध्यम से ऐसी प्रॉक्सी को फिर से चालू करने का प्रयास विफल हो जाएगा, क्योंकि आपको प्रॉक्सी के निर्माता को वास्तविक InvocationHandler उदाहरण पारित करने की आवश्यकता है। सिद्धांत रूप में, जेआरई विशिष्ट लैम्ब्डा अभिव्यक्ति कार्यान्वयन एक समान पैटर्न

उपर्युक्त बिंदुओं को ध्यान में रखते हुए, यह स्पष्ट होना चाहिए कि आप यह नहीं कह सकते कि यह सामान्य रूप से आंतरिक कक्षाओं के साथ काम करता है। इसके लिए आपको कई बाधाएं पूरी करनी होंगी।


क्रमबद्धता के बारे में, यह, serializable लैम्ब्डा भाव के लिए काम करता है क्योंकि लगातार प्रपत्र पूरी तरह से described in this answer के रूप में, क्रम कार्यान्वयन वर्ग से अलग है। इसलिए जेनरेट क्लास का नाम धारावाहिक रूप में निहित नहीं है और deserializing end एक पूरी तरह से अलग रनटाइम कार्यान्वयन हो सकता है।

0

मानचित्र में लैम्ब्डा उदाहरणों को स्टोर करें, उदाहरण के नाम पर कुंजी। आप नक्शे को विश्व स्तर पर उपलब्ध एक सिंगलटन रैपर क्लास (केवल सिंक्रनाइज़ेशन समस्याओं के लिए देखें) कर सकते हैं।

class LambdaMap { 

    private HashMap<String, Consumer<String>> theMap; 

    private LambdaMap() { 
     theMap = new HashMap<>(); 
    } 

    private static class INSTANCE_HOLDER { 
     private static LambdaMap INSTANCE = new LambdaMap(); 
    } 

    public static LambdaMap getInstance() { 
     return INSTANCE_HOLDER.INSTANCE; 
    } 

    public Consumer<String> put(String key, Consumer<String> value) { 
     return theMap.put(key, value); 
    } 

    public static void Call(String aLambdaClassName, String aArg) { 
     Consumer<String> func = getInstance().theMap.get(aLambdaClassName); 
     if (func != null) { 
      func.accept(aArg); 
     } 
    } 

} 

class Host { 
    public static void action(String aMessage) { 
     System.out.println("Goodbye, " + aMessage); 
    } 
} 

public class GlobalLambdas { 

    public static void main(String[] args) { 
     LambdaMap.getInstance().put("print greeting", s -> { 
      System.out.println("Hello, " + s); 
     }); 
     LambdaMap.getInstance().put("print goodbye", Host::action); 

     LambdaMap.Call("print greeting", "John"); 
     LambdaMap.Call("print goodbye", "John"); 
    } 
} 

run: 
Hello, John 
Goodbye, John 
संबंधित मुद्दे