Open gnoyes-mik opened 1 year ago
추가적으로 JDK 11부터 인조 메서드와 생성자는 중첩 기반 액세스 제어로 대체되었기 때문에 더 이상 생성되지 않는다고 합니다
starting with JDK 11, synthetic methods and constructors are no longer generated, as they're superseded by nest-based access control.
람다 내부도 조금더 공부해야 할것같아요.... 😢
https://github.com/back-end-study/effective-java/pull/61
람다는 직렬화 해서는 안되는 이유
오라클 공식문서에서도 람다 표현식과 익명 클래스에 대한 직렬화를 '강력하게' 권장하지 않다
그 이유는 람다 표현식이나 익명 클래스에 대해서 직렬화를 할 때, 자바 컴파일러가 특정 구문에 대해서 Synthetic constructs(인조 구문이 맞는 번역 같음)을 삽입하는데 이 Synthetic constructs는 컴파일러의 구현 방식에 따라서 다를 수 있다. 이 의미는 '.class' 파일도 컴파일러 구현에 따라 다를 수 있음을 의미한다. 내용 보기
결과적으로 위의 이유에 의해서 다른 컴파일러를 사용하고 있는 경우 호환성의 문제가 발생할 수 있기 때문에 직렬화를 하는것은 강하게 권장하지 않는다!
람다를 직렬화 하는 방법
하지만 때에 따라서 람나 표현식이나 익명 클래스가 포함된 클래스를 직렬화를 해야할 때도 있을 수 있다
먼저, 람다가 정의된 클래스를 냅다 직렬화/역직렬화를 해보자
main 메소드에서 테스트 방법은 다음과 같다
main 메소드를 실행 해보면
직렬화를 하려고 할 때
NotSerializableException
이 발생하면서 직렬화에 실패한다..람다 직렬화를 하면 안된다고 했지,, 하지 못한다고는 안 했잖아,,
class 파일을 봐도 별 문제가 없어보이는데..
그렇다,,,! 익명 클래스의 생성,동작 방식은 컴파일 타임에 결정되지만, 람다는 런타임에 실제 호출시 결정된다고 한다. (invokedynamic)
그렇기 때문에 java를 실행 시킬 때
-Djdk.internal.lambda.dumpProxyClasses={output-dir}
옵션을 넣어주게 되면 실제 람다가 생성되는 클래스 파일을 볼 수 있다.우리가 일반적으로 직렬화를 할 때 하는 방식으로 NotSerializableLambdaExpression 클래스에 Serializable 인터페이스를 선언했지만,, 위 옵션으로 생성된 람다의 class 파일을 보면 Serializable 인터페이스를 구현하고 있지 않다..
람다를 직렬화 하려면 타입 캐스트(Type cast)를 해주어야 한다
우리가 선언한 함수형 인터페이스와 Serializeble 인터페이스를 결합한 타입으로 람다식을 타입 캐스팅을 해야된다
예를들어 우리가 사용하고 있는 함수형 인터페이스는 Runnable이고 이를 타입 캐스팅하면 아래와 같다
타입 캐스팅을 해준 뒤 생성된 람다 class 파일을 살펴보면
전 과는 다르게 Runnable과 Serializable 인터페이스를 모두 구현하고 있는것을 볼 수 있다!
타입 캐스트를 해준뒤, 다시 한번 main 메소드로 테스트를 해보자!
정상적으로 잘 동작하는것을 볼 수 있다..👏🏻👏🏻
람다 직렬화의 기본 메커니즘에 대해 더 상세히 알고 싶으면 Serialize a Lambda in Java를 참고하자
정리
관련 소스는 여기에서 볼 수 있습니다