2016-06-24 10 views
8

हालांकि it is possible to serialize a lambda in Java 8, यह strongly discouraged है; यहां तक ​​कि serializing inner classes is discouraged। कारण यह है कि लैम्ब्स किसी अन्य जेआरई पर ठीक से निराश नहीं हो सकता है। हालांकि, इसका मतलब यह नहीं है कि सुरक्षित रूप से लैम्ब्डा को क्रमबद्ध करने का एक तरीका है?लैम्बडा को सुरक्षित रूप से क्रमबद्ध करने के लिए कैसे?

उदाहरण के लिए, कहते हैं कि मैं कुछ इस तरह होना करने के लिए एक वर्ग को परिभाषित:

public class MyClass { 
    private String value; 
    private Predicate<String> validateValue; 

    public MyClass(String value, Predicate<String> validate) { 
     this.value = value; 
     this.validateValue = validate; 
    } 

    public void setValue(String value) { 
     if (!validateValue(value)) throw new IllegalArgumentException(); 
     this.value = value; 
    } 

    public void setValidation(Predicate<String> validate) { 
     this.validateValue = validate; 
    } 
} 

अगर मैं इस तरह वर्ग का एक उदाहरण की घोषणा की, मैं इसे क्रमानुसार नहीं करना चाहिए:

MyClass obj = new MyClass("some value", (s) -> !s.isEmpty()); 

लेकिन

// Could even be a static nested class 
public class IsNonEmpty implements Predicate<String>, Serializable { 
    @Override 
    public boolean test(String s) { 
     return !s.isEmpty(); 
    } 
} 
: क्या हुआ अगर मैं इस तरह वर्ग का एक उदाहरण बना दिया 210
MyClass isThisSafeToSerialize = new MyClass("some string", new IsNonEmpty()); 

क्या यह अब क्रमबद्ध करने के लिए सुरक्षित होगा? मेरी वृत्ति कहती है कि हाँ, यह सुरक्षित होना चाहिए, क्योंकि java.util.function में इंटरफेस का कोई कारण नहीं है कि किसी भी अन्य यादृच्छिक इंटरफेस से अलग तरीके से इलाज किया जाना चाहिए। लेकिन मैं अभी भी सावधान हूँ।

+1

इंटरफेस सीरियलाइजेशन के लिए पूरी तरह से अप्रासंगिक हैं, इसलिए हां, 'भविष्यवाणी' को कार्यान्वित करना किसी भी अन्य इंटरफ़ेस को लागू करने के समान प्रभाव है, * कोई नहीं *। लेकिन आपकी धारणा है कि लैम्ब्स किसी अन्य जेआरई पर ठीक से निराश नहीं हो सकता है।एक [अच्छी तरह से परिभाषित निरंतर प्रतिनिधित्व] है (https://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/SerializedLambda.html)। – Holger

+0

@ होल्गर तो [ऑरैक डॉक्स] क्यों है (https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#serialization) ऐसा लगता है कि वे नहीं करते हैं? – Justin

+1

ठीक है, इसमें [serialization के साथ आंतरिक वर्ग संबंधित समस्याओं] का संदर्भ है (https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html#serialization)। संक्षेप में, यह संभावित रूप से संकलक निर्भरता बना रहा है, जेआरई विशिष्ट मुद्दों पर नहीं। अनुमोदित, पाठ थोड़ा भ्रामक है। और आस-पास के संदर्भ के कब्जे वाले मूल्यों को गलती से क्रमबद्ध करने का खतरा याद रखें, जिसमें 'यह' ... – Holger

उत्तर

9

यह इस बात पर निर्भर करता है कि आप किस प्रकार की सुरक्षा चाहते हैं। ऐसा नहीं है कि serialized lambdas विभिन्न जेआरई के बीच साझा नहीं किया जा सकता है। उनके पास एक अच्छी तरह से परिभाषित निरंतर प्रतिनिधित्व है, SerializedLambda। जब आप अध्ययन करते हैं, यह कैसे काम करता है, तो आप पाएंगे कि यह परिभाषित वर्ग की उपस्थिति पर निर्भर करता है, जिसमें एक विशेष विधि होगी जो लैम्ब्डा का पुनर्निर्माण करेगी।

यह अविश्वसनीय बनाता है कि विशिष्ट कलाकृतियों को संकलित करने की निर्भरता, उदा। सिंथेटिक लक्ष्य विधि, जिसमें कुछ जेनरेट किया गया नाम है, एक अन्य लैम्ब्डा अभिव्यक्ति को सम्मिलित करने या कक्षा को फिर से सम्मिलित करने जैसे सरल परिवर्तन, मौजूदा धारावाहिक लैम्ब्डा अभिव्यक्ति के लिए संगतता को तोड़ सकते हैं।

हालांकि, मैन्युअल रूप से लिखित कक्षाओं का उपयोग करके इसका प्रतिरक्षा नहीं है। स्पष्ट रूप से घोषित serialVersionUID के बिना, डिफ़ॉल्ट एल्गोरिदम private और सिंथेटिक वाले समेत, एक समान कंपाइलर निर्भरता जोड़कर, हैशिंग क्लास कलाकृतियों के द्वारा एक आईडी की गणना करेगा। तो न्यूनतम करने के लिए, यदि आप विश्वसनीय निरंतर रूप चाहते हैं, तो एक स्पष्ट serialVersionUID घोषित करना है।

या आप सबसे मजबूत संभव प्रपत्र की ओर रुख:

public enum IsNonEmpty implements Predicate<String> { 
    INSTANCE; 

    @Override 
    public boolean test(String s) { 
     return !s.isEmpty(); 
    } 
} 

इस निरंतर Serializing, वास्तविक क्रियान्वयन के किसी भी गुण की दुकान नहीं है अपने वर्ग का नाम (और तथ्य यह है कि यह एक enum है, निश्चित रूप से के अलावा) और निरंतर के नाम का संदर्भ। Deserialization पर, उस नाम का वास्तविक अद्वितीय उदाहरण इस्तेमाल किया जाएगा।


ध्यान दें कि serializable lambda expressions may create security issues क्योंकि वे एक उद्देश्य यह है कि लक्ष्य को विधियां प्रारंभ करने की अनुमति देता है पर हाथ होने का एक वैकल्पिक तरीका खोलें। हालांकि, यह सभी धारावाहिक वर्गों पर लागू होता है, क्योंकि आपके प्रश्न में दिखाए गए सभी संस्करण और यह उत्तर जानबूझकर एक ऑब्जेक्ट को बेकार करने की अनुमति देता है जो encapsulated ऑपरेशन का आह्वान करने की इजाजत देता है। लेकिन स्पष्ट क्रमिक वर्गों के साथ, लेखक आमतौर पर इस तथ्य के बारे में अधिक जागरूक होते हैं।

+0

मुझे enum के साथ कोई खतरा नहीं दिखता है; जब serialized, यह मूल रूप से सिर्फ वर्ग का नाम और उदाहरण नाम है। यह एक सुरक्षा मुद्दा कैसा है? क्या समस्या मूल रूप से है कि जब हम ऐसा करने का इरादा नहीं रखते थे तो हमलावर को 'इंस्टेंस' तक पहुंच मिल सकती थी? – Justin

+2

बिल्कुल। कक्षा धारावाहिक बनाना एक अतिरिक्त 'सार्वजनिक' कन्स्ट्रक्टर (या एक्सेसर) जोड़ने जैसा है, जिसका उपयोग तब भी किया जा सकता है जब कक्षा स्वयं 'सार्वजनिक' न हो। 'सामान्य' जैसे सामान्य इंटरफ़ेस के साथ संयोजन में, यह इंगित करता है कि encapsulated ऑपरेशन तक पहुंच प्रदान करना। यदि ऑपरेशन स्वयं महत्वपूर्ण नहीं है, तो कोई समस्या नहीं है। – Holger

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