Класс Enum является сериализуемым, поэтому нет проблем с сериализацией объекта с помощью перечислений. Другой случай - когда у класса есть поля класса java.util.Optional. В этом случае выдается следующее исключение: java.io.NotSerializableException: java.util.Optional
Как бороться с такими классами, как их сериализовать? Можно ли отправлять такие объекты в Remote EJB или через 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
serialization
java-8
optional
Vanarchi
источник
источник
Optional
был помечен какSerializable
, то что произойдет, если будетget()
возвращено что-то, что нельзя сериализовать?NotSerializableException,
конечно, получите .Ответы:
Этот ответ является ответом на вопрос в заголовке: «Разве не обязательно быть сериализуемым?» Короткий ответ: группа экспертов Java Lambda (JSR-335) рассмотрела и отклонила его . Это примечание, и это, и это указывают на то, что основная цель проекта
Optional
- использовать его в качестве возвращаемого значения функций, когда возвращаемое значение может отсутствовать. Цель состоит в том, чтобы вызывающий объект немедленно проверилOptional
и извлек фактическое значение, если оно есть. Если значение отсутствует, вызывающий может подставить значение по умолчанию, создать исключение или применить другую политику. Обычно это делается путем объединения вызовов беглых методов с конца конвейера потока (или других методов), которые возвращаютOptional
значения.Он никогда не предназначался для
Optional
использования другими способами, например, для необязательных аргументов метода или для хранения в виде поля в объекте . И, в более широком смысле, созданиеOptional
сериализуемого позволит ему постоянно храниться или передаваться по сети, что поощряет использование, выходящее далеко за рамки первоначальной цели дизайна.Обычно есть лучшие способы организовать данные, чем хранить их
Optional
в поле. Если получатель (например,getValue
метод в вопросе) возвращает фактическое значениеOptional
из поля, он заставляет каждого вызывающего объекта реализовать некоторую политику для работы с пустым значением. Это, вероятно, приведет к непоследовательному поведению абонентов. Часто лучше, чтобы любой набор кодов в этом поле применял некоторую политику во время ее установки.Иногда люди хотят складывать
Optional
в коллекции, лайкатьList<Optional<X>>
илиMap<Key,Optional<Value>>
. Это тоже обычно плохая идея. Это часто лучше заменить эти обычаиOptional
с Null-объектными значениями (не фактическиеnull
ссылки), или просто опустить эти записи из коллекции целиком.источник
Множество
Serialization
связанных проблем можно решить, отделив постоянную сериализованную форму от фактической реализации среды выполнения, с которой вы работаете.Класс
Optional
реализует поведение, которое позволяет писать хороший код при работе с возможно отсутствующими значениями (по сравнению с использованиемnull
). Но это не добавляет никаких преимуществ постоянному представлению ваших данных. Это просто увеличило бы ваши сериализованные данные ...Приведенный выше эскиз может показаться сложным, но это потому, что он демонстрирует узор только с одним свойством. Чем больше свойств имеет ваш класс, тем больше должна раскрываться его простота.
И не забывайте, возможность полностью изменить реализацию
My
без необходимости адаптировать постоянную форму…источник
class My
, который вы обычно делаете так, как он удобен и для других целей,readResolve
можно реализовать однострочную реализацию, тем самым уменьшив шаблон до одной строки для каждого свойства. Что не так много, учитывая тот факт, что каждое изменяемое свойство вMy
любом случае имеет не менее семи строк кода в классе .Если вы хотите сериализуемую опцию, рассмотрите возможность использования опциональной guava, которая является сериализуемой.
источник
Любопытное упущение.
Вам нужно будет пометить поле как
transient
и предоставить свой собственныйwriteObject()
метод, который записывает самget()
результат, иreadObject()
метод, который восстанавливаетOptional
, считывая результат из потока. Не забывая позвонитьdefaultWriteObject()
иdefaultReadObject()
соответственно.источник
В библиотеке Vavr.io (бывший Javaslang) также есть
Option
класс, который можно сериализовать:источник
Если вы хотите поддерживать более согласованный список типов и избегать использования null, есть одна странная альтернатива.
Вы можете сохранить значение, используя пересечение типов . В сочетании с лямбдой это позволяет что-то вроде:
Наличие
temp
отдельной переменной позволяет избежать закрытия владельцаvalue
члена и, следовательно, слишком частой сериализации.источник