为什么java.util.Optional不是Serializable,如何序列化带有此类字段的对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24547673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:51:42  来源:igfitidea点击:

Why java.util.Optional is not Serializable, how to serialize the object with such fields

javaserializationjava-8optional

提问by vanarchi

The Enum class is Serializable so there is no problem to serialize object with enums. The other case is where class has fields of java.util.Optional class. In this case the following exception is thrown: java.io.NotSerializableException: java.util.Optional

Enum 类是可序列化的,因此使用枚举序列化对象没有问题。另一种情况是 class 具有 java.util.Optional 类的字段。在这种情况下,抛出以下异常: java.io.NotSerializableException: java.util.Optional

How to deal with such classes, how to serialize them? Is it possible to send such objects to Remote EJB or through RMI?

如何处理这样的类,如何序列化它们?是否可以将此类对象发送到远程 EJB 或通过 RMI?

This is the example:

这是示例:

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);
        }
    }
}

采纳答案by Stuart Marks

This answer is in response to the question in the title, "Shouldn't Optional be Serializable?" The short answer is that the Java Lambda (JSR-335) expert group considered and rejected it. That note, and this oneand this oneindicate that the primary design goal for Optionalis to be used as the return value of functions when a return value might be absent. The intent is that the caller immediately check the Optionaland extract the actual value if it's present. If the value is absent, the caller can substitute a default value, throw an exception, or apply some other policy. This is typically done by chaining fluent method calls off the end of a stream pipeline (or other methods) that return Optionalvalues.

这个答案是对标题中的问题的回应,“难道 Optional 不应该是可序列化的吗?” 简短的回答是 Java Lambda (JSR-335) 专家组考虑并拒绝了它。那个注释,这个这个一个表明主要的设计目标Optional是当返回值可能不存在时用作函数的返回值。目的是调用者立即检查Optional并提取实际值(如果存在)。如果该值不存在,调用者可以替换默认值、抛出异常或应用一些其他策略。这通常是通过在返回Optional值的流管道(或其他方法)的末端链接流利的方法调用来完成的。

It was never intended for Optionalto be used other ways, such as for optional method argumentsor to be stored as a field in an object. And by extension, making Optionalserializable would enable it to be stored persistently or transmitted across a network, both of which encourage uses far beyond its original design goal.

它从未打算Optional以其他方式使用,例如用于可选方法参数存储为对象中的字段。并且通过扩展,使可Optional序列化使其能够持久存储或通过网络传输,这两者都鼓励使用远远超出其原始设计目标的用途。

Usually there are better ways to organize the data than to store an Optionalin a field. If a getter (such as the getValuemethod in the question) returns the actual Optionalfrom the field, it forces every caller to implement some policy for dealing with an empty value. This will likely lead to inconsisent behavior across callers. It's often better to have whatever code sets that field apply some policy at the time it's set.

通常有比Optional在字段中存储数据更好的方法来组织数据。如果 getter(例如问题中的getValue方法)Optional从字段中返回实际值,它会强制每个调用者实施一些处理空值的策略。这可能会导致调用者之间的行为不一致。通常最好让该字段在设置时应用某些策略的任何代码集。

Sometimes people want to put Optionalinto collections, like List<Optional<X>>or Map<Key,Optional<Value>>. This too is usually a bad idea. It's often better to replace these usages of Optionalwith Null-Objectvalues (not actual nullreferences), or simply to omit these entries from the collection entirely.

有时人们想放入Optional集合中,例如List<Optional<X>>Map<Key,Optional<Value>>。这通常也是一个坏主意。OptionalNull-Object值(不是实际null引用)替换这些用法通常更好,或者简单地从集合中完全省略这些条目。

回答by user207421

It's a curious omission.

这是一个奇怪的遗漏。

You would have to mark the field as transientand provide your own custom writeObject()method that wrote the get()result itself, and a readObject()method that restored the Optionalby reading that result from the stream. Not forgetting to call defaultWriteObject()and defaultReadObject()respectively.

您必须将该字段标记为transient并提供您自己writeObject()编写get()结果本身的自定义方法,以及通过从流中读取该结果来readObject()恢复 的方法Optional。不要忘记分别调用defaultWriteObject()defaultReadObject()

回答by Holger

A lot of Serializationrelated problems can be solved by decoupling the persistent serialized form from the actual runtime implementation you operate on.

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;
    }
}

The class Optionalimplements behaviorwhich allows to write good code when dealing with possibly absent values (compared to the use of null). But it does not add any benefit to a persistent representation of your data. It would just make your serialized data bigger…

该类Optional实现的行为允许在处理可能不存在的值时编写好的代码(与使用 相比null)。但它不会为数据的持久表示增加任何好处。它只会让你的序列化数据更大......

The sketch above might look complicated but that's because it demonstrates the pattern with one property only. The more properties your class has the more its simplicity should be revealed.

上面的草图可能看起来很复杂,但那是因为它仅用一个属性演示了模式。你的类拥有的属性越多,它的简单性就应该越明显。

And not to forget, the possibility to change the implementation of Mycompletely without any need to adapt the persistent form…

并且不要忘记,可以完全改变实现My而无需调整持久形式......

回答by Eric Hartford

If you would like a serializable optional, consider instead using guava's optionalwhich is serializable.

如果您想要一个可序列化的可选项,请考虑使用番石榴的可序列化的可选项

回答by Przemek Nowak

The Vavr.io library (former Javaslang) also have the Optionclass which is serializable:

Vavr.io 库(前 Javaslang)也有Option可序列化的类:

public interface Option<T> extends Value<T>, Serializable { ... }

回答by Dan Gravell

If you want to maintain a more consistent type list and avoid using null there's one kooky alternative.

如果您想维护更一致的类型列表并避免使用 null,则有一种奇怪的选择。

You can store the value using an intersection of types. Coupled with a lambda, this allows something like:

您可以使用类型的交集存储值。再加上一个 lambda,这允许类似:

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();

Having the tempvariable separate avoids closing over the owner of the valuemember and thus serialising too much.

temp变量分开可以避免关闭value成员的所有者,从而避免过多的序列化。