Klasa Enum jest Serializable, więc nie ma problemu z serializacją obiektu za pomocą wyliczeń. W drugim przypadku klasa ma pola klasy java.util.Optional. W takim przypadku zgłaszany jest następujący wyjątek: java.io.NotSerializableException: java.util.Optional
Jak sobie radzić z takimi klasami, jak je serializować? Czy można wysłać takie obiekty do zdalnego EJB lub przez RMI?
Oto przykład:
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
źródło
źródło
Optional
został oznaczony jakoSerializable
, co by się stało, gdybyget()
zwrócił coś, czego nie można serializować?NotSerializableException,
.Odpowiedzi:
Ta odpowiedź jest odpowiedzią na pytanie w tytule „Czy opcjonalny nie powinien być serializowany?” Krótka odpowiedź jest taka, że grupa ekspertów Java Lambda (JSR-335) rozważyła to i odrzuciła . Ta uwaga, ta i ta wskazują, że głównym celem projektu
Optional
jest użycie jako wartości zwracanej funkcji, gdy wartość zwracana może być nieobecna. Celem jest, aby wywołujący natychmiast sprawdziłOptional
i wyodrębnił rzeczywistą wartość, jeśli jest obecna. Jeśli wartość jest nieobecna, obiekt wywołujący może zastąpić wartość domyślną, zgłosić wyjątek lub zastosować inne zasady. Odbywa się to zwykle przez połączenie wywołań metod płynnych na końcu potoku strumienia (lub innych metod), które zwracająOptional
wartości.Nigdy nie było przeznaczone
Optional
do używania go w inny sposób, na przykład do opcjonalnych argumentów metod lub do przechowywania jako pole w obiekcie . A co za tym idzie, umożliwienieOptional
serializacji umożliwiłoby trwałe przechowywanie lub przesyłanie przez sieć, co zachęca do zastosowań daleko wykraczających poza pierwotny cel projektu.Zwykle istnieją lepsze sposoby organizowania danych niż przechowywanie
Optional
w polu. JeśligetValue
metoda pobierająca (taka jak metoda w pytaniu) zwraca wartość rzeczywistąOptional
z pola, to zmusza każdego wywołującego do zaimplementowania pewnych zasad postępowania z wartością pustą. Prawdopodobnie doprowadzi to do niespójnego zachowania wszystkich rozmówców. Często lepiej jest mieć dowolny kod ustawiany przez to pole, który stosuje pewne zasady w momencie ich ustawiania.Czasami ludzie chcą umieścić je
Optional
w kolekcjach, takich jakList<Optional<X>>
lubMap<Key,Optional<Value>>
. To też jest zazwyczaj zły pomysł. Jest to często lepiej zastąpić te zwyczajeOptional
z Null-Object wartości (a nie rzeczywistenull
referencje), lub po prostu pominąć te wpisy z kolekcji w całości.źródło
Wiele
Serialization
powiązanych problemów można rozwiązać, oddzielając trwały formularz serializowany od rzeczywistej implementacji środowiska uruchomieniowego, na którym działasz.Klasa
Optional
implementuje zachowanie, które pozwala napisać dobry kod w przypadku potencjalnie nieobecnych wartości (w porównaniu do użycianull
). Ale to nie dodaje żadnych korzyści do trwałej reprezentacji twoich danych. To po prostu zwiększyłoby twoje zserializowane dane ...Powyższy szkic może wyglądać na skomplikowany, ale to dlatego, że przedstawia wzór tylko z jedną właściwością. Im więcej właściwości ma twoja klasa, tym bardziej powinna być ujawniona jej prostota.
I nie zapominajmy, że możliwość zmiany wykonania
My
całkowicie bez konieczności dostosowywania trwałej formy…źródło
class My
, który zwykle jest przydatny również w innych zastosowaniach,readResolve
może być implementacją jednowierszową, zmniejszając w ten sposób standardowy schemat do jednego wiersza na właściwość. A to niewiele, biorąc pod uwagę fakt, że każda zmienna właściwość ma i tak co najmniej siedem wierszy kodu w klasieMy
.Jeśli chcesz serializowalny opcjonalny, rozważ zamiast tego użycie opcjonalnego guawy, który można serializować.
źródło
To dziwne zaniedbanie.
Musisz oznaczyć pole jako
transient
i podać własną niestandardowąwriteObject()
metodę, która zapisałaget()
sam wynik, orazreadObject()
metodę, która przywróciła wynikOptional
, odczytując ten wynik ze strumienia. Nie zapomnij zadzwonićdefaultWriteObject()
idefaultReadObject()
odpowiednio.źródło
Biblioteka Vavr.io (dawniej Javaslang) ma również
Option
klasę, którą można serializować:źródło
Jeśli chcesz zachować bardziej spójną listę typów i unikać używania null, jest jedna dziwna alternatywa.
Możesz zapisać wartość, używając przecięcia typów . W połączeniu z lambdą pozwala to na coś takiego:
Oddzielenie
temp
zmiennej pozwala uniknąć zamykania właściciela elementuvalue
członkowskiego, a tym samym zbyt dużej serializacji.źródło