Java.util.Optional Serializable नहीं है, ऐसे क्षेत्रों के साथ ऑब्जेक्ट को कैसे सीरियल करें


107

Enum class Serializable है इसलिए Enums के साथ ऑब्जेक्ट को सीरियल करने के लिए कोई समस्या नहीं है। दूसरा मामला यह है कि वर्ग में java.util.Optional वर्ग के क्षेत्र हैं। इस मामले में निम्नलिखित अपवाद फेंका गया है: java.io.NotSerializableException: java.util.Onional

इस तरह की कक्षाओं से कैसे निपटें, उन्हें कैसे सीरियल करें? क्या ऐसी वस्तुओं को दूरस्थ ईजेबी या आरएमआई के माध्यम से भेजना संभव है?

यह उदाहरण है:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Optional;

import org.junit.Test;

public class SerializationTest {

    static class My implements Serializable {

        private static final long serialVersionUID = 1L;
        Optional<Integer> value = Optional.empty();

        public void setValue(Integer i) {
            this.i = Optional.of(i);
        }

        public Optional<Integer> getValue() {
            return value;
        }
    }

    //java.io.NotSerializableException is thrown

    @Test
    public void serialize() {
        My my = new My();
        byte[] bytes = toBytes(my);
    }

    public static <T extends Serializable> byte[] toBytes(T reportInfo) {
        try (ByteArrayOutputStream bstream = new ByteArrayOutputStream()) {
            try (ObjectOutputStream ostream = new ObjectOutputStream(bstream)) {
                ostream.writeObject(reportInfo);
            }
            return bstream.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

यदि Optionalइसके रूप में चिह्नित किया गया था Serializable, तो क्या होगा यदि get()कुछ ऐसा लौटाया जाए जो धारावाहिक न हो?
डब्ल्यूडब्ल्यू।

10
@WW। आपको जरूर मिलेगा NotSerializableException,
लोर्ने

7
@WW। यह संग्रह की तरह है। अधिकांश संग्रह कक्षाएं क्रमबद्ध हैं, लेकिन एक संग्रह उदाहरण वास्तव में केवल धारावाहिक हो सकता है यदि संग्रह में निहित प्रत्येक वस्तु भी धारावाहिक है।
स्टुअर्ट मार्क्स

मेरा व्यक्तिगत यहाँ है: यह लोगों को वस्तुओं की क्रमिक रूप से इकाई परीक्षण को ठीक से याद दिलाना नहीं है। बस java.io.NotSerializableException (java.util.Optional) में ही भाग गया ... ?
GhostCat

जवाबों:


171

यह जवाब शीर्षक में सवाल के जवाब में है, "वैकल्पिक नहीं होना चाहिए सीरियल?" संक्षिप्त उत्तर यह है कि जावा लैम्ब्डा (JSR-335) विशेषज्ञ समूह ने इस पर विचार किया और इसे खारिज कर दिया । वह नोट, और यह एक और यह एक दर्शाता है कि प्राथमिक डिज़ाइन लक्ष्य का Optionalउपयोग फ़ंक्शंस के रिटर्न मान के रूप में किया जाना है जब रिटर्न वैल्यू अनुपस्थित हो सकती है। आशय यह है कि कॉल करने वाला तुरंत जाँच करे Optionalऔर मौजूद होने पर वास्तविक मूल्य निकाले। यदि मान अनुपस्थित है, तो कॉल करने वाला डिफ़ॉल्ट मान को प्रतिस्थापित कर सकता है, एक अपवाद फेंक सकता है, या कुछ अन्य नीति लागू कर सकता है। यह आम तौर पर धाराप्रवाह विधि (या अन्य विधियों) के अंत से बंद धाराप्रवाह कॉलिंग द्वारा किया जाता है जो Optionalमान लौटाते हैं।

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

आमतौर पर डेटा को Optionalकिसी फ़ील्ड में संग्रहीत करने की तुलना में व्यवस्थित करने के बेहतर तरीके हैं । यदि कोई गेटर (जैसे getValueप्रश्न में विधि) वास्तविक Optionalको क्षेत्र से लौटाता है , तो यह प्रत्येक कॉलर को खाली मूल्य से निपटने के लिए कुछ नीति लागू करने के लिए मजबूर करता है। यह संभवतः कॉल करने वालों के बीच असंगत व्यवहार को बढ़ावा देगा। यह अक्सर बेहतर होता है कि जो भी कोड सेट करता है वह फ़ील्ड उस समय निर्धारित की गई कुछ नीति लागू करता है।

कभी-कभी लोग Optionalसंग्रह में रखना चाहते हैं , जैसे List<Optional<X>>या Map<Key,Optional<Value>>। यह भी आमतौर पर एक बुरा विचार है। यह के इन प्रयोगों को बदलने के लिए अक्सर बेहतर है Optionalके साथ अशक्त-वस्तु मूल्यों (न कि वास्तविक nullसंदर्भ), या बस छोड़ पूरी तरह से संग्रह से इन प्रविष्टियों।


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

1
सुतार के उत्तर के पीछे तर्क पर यह एक उत्कृष्ट ब्लॉग पोस्ट है: blog.joda.org/2014/11/optional-in-java-se-8.html
वेस्ले हार्टफ़ोर्ड

2
अच्छी बात यह है कि मुझे क्रमिक क्षेत्रों का उपयोग करने की आवश्यकता नहीं है। यह अन्यथा एक आपदा होगी
कुरु

48
दिलचस्प जवाब, मेरे लिए कि डिजाइन की पसंद पूरी तरह से अस्वीकार्य और गुमराह थी। आप कहते हैं, "आमतौर पर एक क्षेत्र में एक वैकल्पिक स्टोर करने की तुलना में डेटा को व्यवस्थित करने के बेहतर तरीके हैं", निश्चित रूप से, शायद, क्यों नहीं, लेकिन यह डिजाइनर की पसंद होनी चाहिए, न कि भाषा की। यह इन मामलों में जहां मैं गहराई से जावा में याद आती है स्काला optionals का एक और एक है (स्काला optionals Serializable हैं, और वे इकाई के दिशा निर्देशों का पालन करें)
Guillaume

37
"वैकल्पिक के लिए प्राथमिक डिज़ाइन लक्ष्य का उपयोग फ़ंक्शंस के रिटर्न मान के रूप में किया जाना है, जब रिटर्न वैल्यू अनुपस्थित हो सकती है।" ठीक है, ऐसा लगता है कि आप दूरस्थ ईजेबी में रिटर्न वैल्यू के लिए उनका उपयोग नहीं कर सकते। महान ...
थिलो

15

Serializationआपके द्वारा संचालित वास्तविक रनटाइम कार्यान्वयन से लगातार क्रमबद्ध फ़ॉर्म को डिकूप करके बहुत सारी संबंधित समस्याओं को हल किया जा सकता है।

/** The class you work with in your runtime */
public class My implements Serializable {
    private static final long serialVersionUID = 1L;

    Optional<Integer> value = Optional.empty();

    public void setValue(Integer i) {
        this.value = Optional.ofNullable(i);
    }

    public Optional<Integer> getValue() {
        return value;
    }
    private Object writeReplace() throws ObjectStreamException
    {
        return new MySerialized(this);
    }
}
/** The persistent representation which exists in bytestreams only */
final class MySerialized implements Serializable {
    private final Integer value;

    MySerialized(My my) {
        value=my.getValue().orElse(null);
    }
    private Object readResolve() throws ObjectStreamException {
        My my=new My();
        my.setValue(value);
        return my;
    }
}

वर्ग व्यवहार कोOptional लागू करता है जो संभवतः अनुपस्थित मूल्यों (उपयोग के मुकाबले null) की तुलना में अच्छा कोड लिखने की अनुमति देता है । लेकिन यह आपके डेटा के लगातार प्रतिनिधित्व के लिए कोई लाभ नहीं जोड़ता है। यह सिर्फ आपके क्रमबद्ध डेटा को बड़ा बना देगा ...

ऊपर स्केच जटिल लग सकता है लेकिन ऐसा इसलिए है क्योंकि यह केवल एक संपत्ति के साथ पैटर्न प्रदर्शित करता है। आपकी कक्षा में जितनी अधिक संपत्तियाँ हैं, उसकी सादगी उतनी ही अधिक होनी चाहिए।

और भूल नहीं करने के Myलिए, लगातार फार्म को अनुकूलित करने की आवश्यकता के बिना पूरी तरह से कार्यान्वयन को बदलने की संभावना …


2
+1, लेकिन अधिक फ़ील्ड्स के साथ उन्हें कॉपी करने के लिए अधिक बॉयलरप्लेट होंगे।
मार्को टोपोलनिक

1
@ मार्को टोपोलनिक: अधिकतम, संपत्ति और दिशा के अनुसार एक सिंगल लाइन। हालाँकि, के लिए एक उपयुक्त कंस्ट्रक्टर प्रदान करके class My, जिसे आप आमतौर पर अन्य उपयोगों के लिए भी उपयोग करते हैं, readResolveएक एकल-पंक्ति कार्यान्वयन हो सकता है , इस प्रकार बॉयलरप्लेट को प्रति पंक्ति एक लाइन में कम किया जा सकता है। इस तथ्य को अधिक महत्व नहीं दिया गया है कि प्रत्येक उत्परिवर्तनीय संपत्ति में Myवैसे भी कक्षा में कम से कम सात लाइनें हैं ।
होल्गर

मैंने उसी विषय को कवर करते हुए एक पोस्ट लिखी। यह अनिवार्य रूप से इस उत्तर का लंबा पाठ संस्करण है: सीरियलाइज़ ऑप्शनल
निकोलई

नकारात्मक पक्ष यह है: आपको वैकल्पिक उपयोग करने वाले किसी भी सेम / पोजो के लिए ऐसा करने की आवश्यकता है। लेकिन फिर भी, अच्छा विचार है।
घोस्टकट


4

यह एक उत्सुक चूक है।

आपको फ़ील्ड को चिह्नित करना होगा transientऔर अपनी स्वयं की कस्टम writeObject()विधि प्रदान करनी होगी जो get()परिणाम को स्वयं लिखती है, और एक readObject()विधि जिसने Optionalस्ट्रीम से उस परिणाम को पढ़कर पुनर्स्थापित किया है। क्रमशः कॉल defaultWriteObject()और कॉल करना न भूलें defaultReadObject()


यदि मैं एक वर्ग के कोड का स्वामी हूं तो किसी क्षेत्र में मात्र वस्तु को संग्रहीत करना अधिक सुविधाजनक है। ऐसे मामले में वैकल्पिक वर्ग को कक्षा के इंटरफ़ेस के लिए प्रतिबंधित किया जाएगा (प्राप्त करें विधि Optional.ofNullable (फ़ील्ड) वापस आ जाएगी)। लेकिन आंतरिक प्रतिनिधित्व के लिए यह स्पष्ट रूप से यह मानने के लिए वैकल्पिक का उपयोग करना संभव नहीं है कि मूल्य वैकल्पिक है।
वंचि

मैं सिर्फ दिखाया है कि यह है संभव। यदि आप किसी कारण से अन्यथा सोचते हैं, तो वास्तव में आपका प्रश्न क्या है?
लोर्ने

आपके उत्तर के लिए धन्यवाद, यह मेरे लिए एक विकल्प जोड़ता है। अपनी टिप्पणी में मैं इस विषय पर आगे के विचार दिखाना चाहता हूं, प्रत्येक समाधान के प्रो और गर्भ पर विचार करें। उपयोग राइटऑबजेक्ट / रीडऑब्जेक्ट विधियों में हमारे पास राज्य प्रतिनिधित्व में वैकल्पिक का स्पष्ट इरादा है, लेकिन क्रमबद्धता का कार्यान्वयन अधिक जटिल हो जाता है। यदि फ़ील्ड का उपयोग गणना / धाराओं में गहन रूप से किया जाता है - राइटऑबजेक्ट / रीडऑबजेक्ट का उपयोग करने के लिए अधिक सुविधाजनक है।
वानरची

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


0

यदि आप एक अधिक सुसंगत प्रकार की सूची बनाए रखना चाहते हैं और अशक्त एक वैकल्पिक विकल्प का उपयोग करने से बचना चाहते हैं।

आप प्रकारों के प्रतिच्छेदन का उपयोग करके मूल्य को संग्रहीत कर सकते हैं । एक लंबोदर के साथ युग्मित, यह कुछ इस तरह की अनुमति देता है:

private final Supplier<Optional<Integer>> suppValue;
....
List<Integer> temp = value
        .map(v -> v.map(Arrays::asList).orElseGet(ArrayList::new))
        .orElse(null);
this.suppValue = (Supplier<Optional<Integer>> & Serializable)() -> temp==null ? Optional.empty() : temp.stream().findFirst();

होने tempके मालिक के ऊपर बंद करने चर अलग टाल valueसदस्य है और इस तरह बहुत ज्यादा serialising।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.