为什么java.util.Optional不是Serializable,如何使用这些字段序列化对象
Enum类是Serializable,因此使用枚举序列化对象没有问题。另一种情况是class具有java.util.Optional类的字段。在这种情况下抛出以下异常:java.io.NotSerializableException:java.util.Optional
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
如何处理这些类,如何序列化它们?是否可以将此类对象发送到远程EJB或通过RMI?
How to deal with such classes, how to serialize them? Is it possible to send such objects to Remote EJB or through RMI?
这是示例:
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);
}
}
}
这个答案是对标题中的问题的回答:不应该是可序列化的吗?简短的回答是Java Lambda(JSR-335)专家组考虑并拒绝了它。那个说明,这个和这一个表明主要设计当返回值可能不存在时,可选
的目标将用作函数的返回值。目的是调用者立即检查 Optional
并提取实际值(如果存在)。如果该值不存在,则调用者可以替换默认值,抛出异常或应用其他一些策略。这通常通过在流管道(或其他方法)的末尾链接流式方法调用来完成,该管道返回可选
值。
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 one and this one indicate that the primary design goal for Optional
is 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 Optional
and 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 Optional
values.
从来没有打算以其他方式使用 Optional
,例如可选方法参数或存储作为对象中的字段。通过扩展,使可选
序列化可以使其永久存储或通过网络传输,这两者都鼓励使用远远超出其原始设计目标。
It was never intended for Optional
to be used other ways, such as for optional method arguments or to be stored as a field in an object. And by extension, making Optional
serializable would enable it to be stored persistently or transmitted across a network, both of which encourage uses far beyond its original design goal.
通常有更好的方法来组织数据,而不是在字段中存储 Optional
。如果getter(例如问题中的 getValue
方法)从字段中返回实际的 Optional
,则会强制每个调用者实现一些处理空值的策略。这可能会导致呼叫者之间出现不一致的行为。在设置字段时应该使用任何代码集通常会更好。
Usually there are better ways to organize the data than to store an Optional
in a field. If a getter (such as the getValue
method in the question) returns the actual Optional
from 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.
有时人们想放可选
进入集合,例如列表<可选< X>>
或地图< Key,可选< Value>>
。这也是一个坏主意。使用 Null-替换 Optional
的这些用法通常会更好。对象值(不是实际的 null
引用),或者只是完全忽略集合中的这些条目。
Sometimes people want to put Optional
into 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 Optional
with Null-Object values (not actual null
references), or simply to omit these entries from the collection entirely.