Die Enum-Klasse ist serialisierbar, sodass es kein Problem gibt, Objekte mit Enums zu serialisieren. Der andere Fall ist, wenn die Klasse Felder der Klasse java.util.Optional enthält. In diesem Fall wird die folgende Ausnahme ausgelöst: java.io.NotSerializableException: java.util.Optional
Wie gehe ich mit solchen Klassen um, wie serialisiere ich sie? Ist es möglich, solche Objekte an Remote EJB oder über RMI zu senden?
Dies ist das Beispiel:
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
quelle
quelle
Optional
markiert alsSerializable
, was würde dann passieren, wennget()
etwas zurückgegeben würde, das nicht serialisierbar war?NotSerializableException,
natürlich eine bekommen.Antworten:
Diese Antwort ist eine Antwort auf die Frage im Titel: "Sollte Optional nicht serialisierbar sein?" Die kurze Antwort lautet, dass die Expertengruppe Java Lambda (JSR-335) dies geprüft und abgelehnt hat . Dieser und dieser sowie dieser Hinweis geben an, dass das primäre Entwurfsziel für darin
Optional
besteht, als Rückgabewert von Funktionen verwendet zu werden, wenn möglicherweise kein Rückgabewert vorhanden ist. Die Absicht ist, dass der AnruferOptional
den aktuellen Wert sofort überprüft und extrahiert, falls vorhanden. Wenn der Wert nicht vorhanden ist, kann der Aufrufer einen Standardwert ersetzen, eine Ausnahme auslösen oder eine andere Richtlinie anwenden. Dies erfolgt normalerweise durch Verketten fließender Methodenaufrufe am Ende einer Stream-Pipeline (oder anderer Methoden), dieOptional
Werte zurückgeben.Es war niemals dafür gedacht
Optional
, auf andere Weise verwendet zu werden, beispielsweise für optionale Methodenargumente oder als Feld in einem Objekt gespeichert zu werden . Durch dieOptional
Serialisierung kann es dauerhaft gespeichert oder über ein Netzwerk übertragen werden. Beides fördert die Verwendung weit über das ursprüngliche Entwurfsziel hinaus.Normalerweise gibt es bessere Möglichkeiten, die Daten zu organisieren, als sie
Optional
in einem Feld zu speichern . Wenn ein Getter (wie diegetValue
Methode in der Frage) das IstOptional
aus dem Feld zurückgibt , zwingt er jeden Aufrufer, eine Richtlinie für den Umgang mit einem leeren Wert zu implementieren. Dies führt wahrscheinlich zu einem inkonsistenten Verhalten aller Anrufer. Es ist oft besser, wenn die Codesätze in diesem Feld zum Zeitpunkt der Festlegung eine Richtlinie anwenden.Manchmal möchten Leute
Optional
in Sammlungen setzen, wieList<Optional<X>>
oderMap<Key,Optional<Value>>
. Auch das ist normalerweise eine schlechte Idee. Oft ist es besser, diese VerwendungenOptional
durch Null-Objekt- Werte (keine tatsächlichennull
Referenzen) zu ersetzen oder diese Einträge einfach vollständig aus der Sammlung zu streichen.quelle
Viel
Serialization
verwandte Probleme können gelöst werden, indem Sie das persistente serialisierte Formular von der tatsächlichen Laufzeitimplementierung entkoppeln, mit der Sie arbeiten.Die Klasse
Optional
implementiert ein Verhalten, das es ermöglicht, guten Code zu schreiben, wenn möglicherweise fehlende Werte verarbeitet werden (im Vergleich zur Verwendung vonnull
). Eine dauerhafte Darstellung Ihrer Daten bietet jedoch keinen Vorteil. Es würde nur Ihre serialisierten Daten größer machen ...Die obige Skizze mag kompliziert aussehen, aber das liegt daran, dass sie das Muster nur mit einer Eigenschaft demonstriert. Je mehr Eigenschaften Ihre Klasse hat, desto mehr sollte ihre Einfachheit offenbart werden.
Und nicht zu vergessen, die Möglichkeit, die Implementierung
My
komplett zu ändern, ohne die persistente Form anpassen zu müssen…quelle
class My
, den Sie normalerweise auch für andere Zwecke verwenden,readResolve
kann jedoch eine einzeilige Implementierung sein, wodurch die Boilerplate auf eine einzige Zeile pro Eigenschaft reduziert wird. Was angesichts der Tatsache, dass jede veränderbare EigenschaftMy
ohnehin mindestens sieben Codezeilen in der Klasse hat, nicht viel ist.Wenn Sie eine serialisierbare Option wünschen, sollten Sie stattdessen die optionale Option der Guave verwenden, die serialisierbar ist.
quelle
Es ist eine merkwürdige Auslassung.
Sie müssten das Feld als markieren
transient
und Ihre eigene benutzerdefiniertewriteObject()
Methode angeben , mit der dasget()
Ergebnis selbst geschrieben wurde, sowie einereadObject()
Methode, mit derOptional
das Ergebnis wiederhergestellt wird, indem das Ergebnis aus dem Stream gelesen wird. Nicht zu vergessen , rufendefaultWriteObject()
unddefaultReadObject()
jeweils.quelle
Die Vavr.io-Bibliothek (ehemals Javaslang) hat auch die
Option
Klasse, die serialisierbar ist:quelle
Wenn Sie eine konsistentere Typliste pflegen und die Verwendung von Null vermeiden möchten, gibt es eine verrückte Alternative.
Sie können den Wert über einen Schnittpunkt von Typen speichern . In Verbindung mit einem Lambda ermöglicht dies Folgendes:
Wenn die
temp
Variable getrennt ist, wird vermieden, dass der Eigentümer desvalue
Mitglieds geschlossen wird und zu viel serialisiert wird.quelle