Enum 클래스는 Serializable이므로 객체를 열거 형으로 직렬화하는 데 문제가 없습니다. 다른 경우는 클래스에 java.util.Optional 클래스의 필드가있는 경우입니다. 이 경우 다음 예외가 발생합니다. java.io.NotSerializableException : java.util.Optional
이러한 클래스를 처리하는 방법, 직렬화하는 방법은 무엇입니까? 이러한 개체를 원격 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 Lambda (JSR-335) 전문가 그룹이이를 고려하고 거부 했다는 것 입니다. 그 노트, 그리고 이것 과 이것 하나 는 Optional
반환 값이 없을 때 함수의 반환 값으로 사용되는 기본 디자인 목표를 나타냅니다 . 의도는 호출자가 즉시 확인 Optional
하고 실제 값이있는 경우 추출하는 것입니다. 값이 없으면 호출자는 기본값을 대체하거나 예외를 발생 시키거나 다른 정책을 적용 할 수 있습니다. 이는 일반적으로 Optional
값 을 반환하는 스트림 파이프 라인 (또는 다른 메서드)의 끝에서 유연한 메서드 호출을 연결하여 수행됩니다 .
선택적 메서드 인수Optional
와 같은 다른 방법으로 사용 하거나 객체의 필드 로 저장 하기위한 것이 아닙니다 . 확장하면 직렬화가 가능해지면서 지속적으로 저장되거나 네트워크를 통해 전송 될 수 있으며, 두 가지 모두 원래 설계 목표를 훨씬 뛰어 넘는 사용을 장려합니다.Optional
일반적으로 Optional
필드에 를 저장하는 것보다 데이터를 구성하는 더 좋은 방법이 있습니다 . getter (예 : getValue
질문 의 메서드)가 Optional
필드 에서 실제 값 을 반환하면 모든 호출자가 빈 값을 처리하기위한 일부 정책을 구현하도록합니다. 이로 인해 발신자간에 일관성없는 동작이 발생할 수 있습니다. 필드가 설정된 시점에 정책을 적용하는 코드 세트를 갖는 것이 더 나은 경우가 많습니다.
때때로 사람들은 또는 Optional
같은 컬렉션 에 넣고 싶어합니다 . 이것도 일반적으로 나쁜 생각입니다. 그것은 이러한 용도로 교체하는 것이 좋습니다 와 널 개체 값 (실제적인 전체 컬렉션에서, 또는 단순히 생략 이러한 항목을 참조).List<Optional<X>>
Map<Key,Optional<Value>>
Optional
null
답변
작업하는 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;
}
}
이 클래스 Optional
는 ( 를 사용하는 것과 비교하여) 없을 가능성이있는 값을 처리 할 때 좋은 코드를 작성할 수있는 동작 을 구현 null
합니다. 그러나 데이터의 지속적인 표현에 어떤 이점도 추가하지 않습니다. 직렬화 된 데이터를 더 크게 만들뿐입니다.
위의 스케치는 복잡해 보일 수 있지만 하나의 속성으로 만 패턴을 보여주기 때문입니다. 클래스에 속성이 많을수록 단순성이 더 많이 드러납니다.
그리고 잊지 말아야 My
할 것은 영구적 인 형태를 적용 할 필요없이 완전히 구현을 변경할 수 있다는 것입니다 .
답변
직렬화 가능한 옵션을 원한다면 직렬화 가능한 구아바의 옵션 을 대신 사용 하는 것이 좋습니다.
답변
이상한 누락입니다.
필드를로 표시하고 결과 자체 를 작성한 transient
사용자 지정 writeObject()
메서드 get()
와 스트림에서 해당 결과를 읽어를 readObject()
복원 하는 메서드를 제공 Optional
해야합니다. 전화하는 것을 잊지 defaultWriteObject()
않고 defaultReadObject()
각각.
답변
Vavr.io 라이브러리 (이전 Javaslang)에는 Option
직렬화 가능한 클래스 도 있습니다 .
public interface Option<T> extends Value<T>, Serializable { ... }
답변
보다 일관된 유형 목록을 유지하고 null을 사용하지 않으려면 한 가지 이상한 대안이 있습니다.
유형의 교차를 사용하여 값을 저장할 수 있습니다 . 람다와 함께 사용하면 다음과 같은 결과를 얻을 수 있습니다.
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();
갖는 temp
의 소유자를 통해 폐쇄 변수 별도을 피 value
구성원 때문에 너무 많은 serialising.