JAVA/Effective Java 90

[아이템 90] 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라

앞서 아이템 87, 아이템 88, 그리고 아이템 89에서 언급했던 것처럼 Serializable을 구현하기로 결정한 순간 언어의 생성자 이외의 방법으로도 인스턴스를 생성할 수 있게 됨에 따라 버그 및 보안 문제가 발생할 가능성이 커집니다.위 문제를 해결하기 위해 커스텀 직렬화, readObject() 또는 readResolve()를 직접 구현하여 위험성을 낮출 수 있지만, 직렬화 프록시 패턴(Serialization Proxy Pattern)을 사용하여 위험을 낮출 수도 있습니다.직렬화 프록시 패턴은 일반적으로 아이템 88에서 다룬 readObject()의 방어적 복사보다 강력함 직렬화 프록시 패턴바깥 클래스의 논리적 상태를 정밀하게 표현하는 중첩 클래스를 설계해 private static으로 선언해당 ..

JAVA/Effective Java 2024.05.19

[아이템 89] 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라

싱글턴이란?클래스의 인스턴스가 오직 1개만 생성되는 것을 보장하는 디자인 패턴 싱글턴 객체를 직렬화할 때 발생하는 문제점클래스에 마커 인터페이스인 Serializable을 구현하는 순간 더 이상 싱글턴 객체가 아님아이템 87에서 언급한 커스텀 직렬화를 사용하더라도, 아이템 88에서 언급한 커스텀 readObject() 메서드를 사용하더라도 소용없음어떤 readObject() 메서드를 선언하든 해당 클래스가 초기화될 때 만들어진 인스턴스와는 별개인 인스턴스를 반환 readResolve() 기능을 이용할 때readObject()가 생성한 인스턴스를 다른 것으로 대체 가능역직렬화한 객체의 클래스가 readResolve() 메서드를 적절히 구현했다면 역직렬화 후 새로 생성된 객체를 인수로 해당 메서드가 호출되고..

JAVA/Effective Java 2024.05.18

[아이템 88] readObject 메서드는 방어적으로 작성하라

아이템 50에서 불변인 날짜 범위 클래스를 생성할 때 가변 객체인 Date 필드를 이용했습니다.이 때문에 불변식을 지키고 유지하기 위해 모든 생성자와 접근자에 Date 객체를 방어적으로 복사하느라 코드가 상당히 길어졌던 것을 기억할 것입니다.   아이템 87에서 언급했다시피 객체의 물리적 표현과 논리적 표현이 동일할 경우 기본 직렬화를 사용해도 됩니다.따라서 위 Period 클래스가 단순히 마커 인터페이스인 Serializable를 구현하도록 수정하면 완벽한 직렬화 적용이 완료되었을 것이라고 생각이 들 것입니다.하지만 위와 같이 적용해서는 주요한 Date 객체의 불변식을 보장하지 못합니다. Period 객체가 단순히 Serializable을 구현했을 때 발생하는 문제점readObject() 메서드가 실질..

JAVA/Effective Java 2024.05.18

[아이템 87] 커스텀 직렬화 형태를 고려해보라

개발 일정에 쫓기는 상황이라면 세부적인 구현에 집중하기보다는 이번 릴리즈에 대충 동작은 하도록 API 설계에 노력을 집중하는 편이 낫습니다.하지만 클래스가 Serializable 구현체이고 기본 직렬화 형태를 사용한다면 기본 직렬화 형태를 버릴 수 없게 되기 때문에 다음 릴리즈 때 버리려 한 대충 동작하는 현재의 구현에 영원히 발이 묶이게 됩니다. 먼저 고민해보고 괜찮다고 판단될 경우에만 기본 직렬화 형태를 사용하자기본 직렬화 형태는 유연성, 성능, 정확성 측면에서 신중히 고민한 후 합당할 때만 사용하는 것을 권장직접 설계하더라도 기본 직렬화 형태와 거의 같은 결과가 나올 경우에만 기본 형태를 사용기본 직렬화 형태는 해당 객체를 루트로 하는 객체 그래프의 물리적 모습을 나름 효율적으로 인코딩한 형태객체가..

JAVA/Effective Java 2024.05.14

[아이템 86] Serializable을 구현할지는 신중히 결정하라

클래스 인스턴스를 직렬화하기 위해서는 단순히 마커 인터페이스인 Serializable을 구현하면 됩니다.이처럼 너무 쉽게 적용할 수 있기 때문에 프로그래머가 특별히 신경 쓸 것이 없다는 오해가 생길 수 있지만 실제로는 직렬화를 적용하는 것은 아주 값비싼 일입니다. Serializable을 구현할 경우 릴리즈한 뒤에는 수정하기 어려움클래스가 Serializable 구현체일 경우 직렬화 형태인 바이트 스트림 인코딩도 하나의 공개 API가 됨자바는 하위 호환성을 지원하는 것을 추구하기 때문에 직렬화된 클래스가 널리 쓰이는 라이브러리에 포함될 경우 릴리즈 이후에는 직렬화 형태도 영원히 지원해야 함클래스의 private과 package-private 인스턴스 필드마저 API로 공개하는 꼴이 되어 객체지향의 핵심인..

JAVA/Effective Java 2024.05.12

[아이템 85] 자바 직렬화의 대안을 찾으라

자바 직렬화란?자바 객체를 바이트 스트림으로 변환하는 메커니즘객체를 파일에 저장하거나 네트워크를 통해 DB 혹은 메모리로 전송할 때 유용직렬화된 객체는 나중에 다시 역직렬화될 수 있어 객체의 상태를 보존하고 복원할 수 있음직렬화를 사용하기 위해서는 클래스가 Serializable 인터페이스 구현체여야 함직렬화된 객체는 ObjectOutputStream을 사용하여 생성된 출력 스트림으로 쓰이며 이를 통해 객체를 스트림에 쓰면 자동으로 필드 값들이 바이트로 변환되어 출력역직렬화는 직렬화된 객체를 읽어와서 자바 객체로 변환하는 것이며 이를 위해 ObjectInputStream을 사용직렬화를 통해 생성된 바이트 스트림은 플랫폼에 독립적이기 때문에 타 플랫폼에서도 역직렬화가 가능 자바 직렬화의 취약점앞선 설명만 ..

JAVA/Effective Java 2024.05.12

[아이템 84] 프로그램의 동작을 쓰레드 스케줄러에 기대지 말라

1. 서론 여러 쓰레드가 실행 중일 경우 OS의 쓰레드 스케줄러가 어떤 쓰레드를 얼마나 오래 실행할지 결정 OS마다 구체적인 스케줄링 정책은 다를 수 있기 때문에 특정 정책에 의존해서는 안됨 정확성이나 성능이 쓰레드 스케줄러에 종속적인 프로그램이라면 타 플랫폼에 이식하기 어려움 2. 좋은 프로그램을 작성하기 위한 원칙 다음 원칙을 지키면 쓰레드 스케줄링 정책이 변경되어도 크게 영향받지 않습니다. 프로세서 수보다 실행 가능한 쓰레드의 평균 수가 지나치게 많아지지 않도록 설정 실행 준비가 된 쓰레드들은 맡은 작업을 완료할 때까지 계속 실행되어야 함 3. 실행 가능한 쓰레드 수를 적게 유지하기 위한 원칙 각 쓰레드가 작업을 완료한 뒤 다음 작업이 생길 때까지 대기하도록 하는 것이 중요 이는 ThreadPool..

JAVA/Effective Java 2024.04.22

[아이템 83] 지연 초기화는 신중히 사용하라

지연 초기화 필드의 초기화 시점을 해당 값이 처음 필요할 때까지 늦추는 기법 값이 전혀 쓰이지 않을 경우 초기화가 일어나지 않음 정적 필드와 인스턴스 필드 모두 적용 가능 주로 최적화 용도로 쓰이지만, 클래스와 인스턴스 초기화 시 발생하는 `위험한 순환` 문제를 해결하는 효과도 있음 위험한 순환(Perilous Cycle) 문제는 초기화하는 동안 객체가 자기 자신을 참조하는 경우에 발생할 수 있는 문제 ex) 클래스나 객체의 생성자에서 다른 객체를 생성하고, 이 생성된 객체가 다시 자신을 참조하는 경우 위험한 순환 문제가 발생 (무한 루프) 1. 지연 초기화는 필요할 때까지는 하지 말자 지연 초기화는 양날의 검 클래스 혹은 인스턴스 생성 시 발생하는 초기화 비용은 줄지만 지연 초기화하는 필드에 접근하는 ..

JAVA/Effective Java 2024.04.11

[아이템 82] 쓰레드 안전성 수준을 문서화하라

한 메서드를 여러 쓰레드가 동시에 호출할 때, 해당 메서드가 어떻게 동작하는지는 해당 클래스와 이를 사용하는 클라이언트 간의 중요한 정보입니다. 이러한 정보가 API 문서에 포함되지 않으면 클래스 사용자는 이 관계를 추측해야 합니다. 그러나 이러한 추측이 틀릴 경우 클라이언트 프로그램은 동기화를 충분히 하지 못하거나 과도하게 동기화하여 성능 문제나 오류를 발생시킬 수 있습니다. 따라서 API 문서에 이러한 정보를 명시하는 것이 중요합니다. synchronized 한정자 API 문서에 synchronized 한정자가 있는 메서드는 안전하다고 간주하는 개발자들이 많은데, 이는 몇 가지 이유로 틀린 생각 메서드 선언에 synchronized 한정자를 선언할지는 구현 이슈일 뿐 API에 속하지 않기 때문에 Ja..

JAVA/Effective Java 2024.04.07

[아이템 81] wait와 notify보다는 동시성 유틸리티를 애용하라

wait(), notify(), notifyAll() 자바 5+ 버전에서 도입된 고수준의 동시성 유틸리티가 wait(), notify()로 하드 코딩해야 했던 일들을 대신 처리해 주기 때문에 현재는 wait()와 notify(), notifyAll() 메서드를 직접 호출해야 할 일이 많이 줄어듦 또한, wait()와 notify()는 올바르게 사용하기 까다롭기 때문에 java.util.concurrent의 고수준 동시성 유틸리티를 사용하는 것을 권장 고수준 동시성 유틸리티의 예는 다음과 같음 ExecutorService ConcurrentHashMap과 같은 Concurrent Collection Synchronizer 1. wait()와 notify()를 사용해야하는 케이스 새로운 코드라면 언제나 wa..

JAVA/Effective Java 2024.04.07