목록Backend/Effective Java (11)
elevne's Study Note
아이템 85. 자바 직렬화의 대안을 찾으라 직렬화는 공격 범위가 너무 넓고 지속적으로 더 넓어져 방어하기 어렵다는 근본적인 문제를 갖는다. ObjectInputStream 의 readObject 메소드를 호출하면서 객체 그래프가 역직렬화되기 때문이다. readObject 메소드는 클래스 패스 안의 거의 모든 타입의 객체를 만들어낼 수 있는 생성자다. 바이트 스트림을 역직렬화하는 과정에서 이 메소드는 그 타입들 안의 코드를 수행할 수 있다. (그 타입들의 코드 전체가 공격 범위 내에 들어간다는 뜻) 신뢰할 수 없는 스트림을 역직렬화하면 원격 코드 실행, 서비스 거부 등의 공격으로 이어질 수 있다. 공격자와 보안 전문가들은 자바 라이브러리와 널리 쓰이는 서드파티 라이브러리에서 직렬화 가능 타입들을 연구하여 ..

아이템 78. 공유 중인 가변 데이터는 동기화해 사용하라 synchronized 키워드는 해당 메소드나 블록을 한 번에 한 스레드씩만 수행하도록 보장한다. 한 객체가 일관된 상태를 가지고 생성되고, 이 객체에 접근하는 메소드는 그 객체에 Lock 을 건다. 락을 건 메소드는 객체의 상태를 확인하고 필요하면 수정한다. 동기화를 통해 객체가 항상 일관된 상태로 유지되게끔 할 수 있다. 또한, 동기화를 사용하지 않는다면 한 쓰레드가 만든 변화를 다른 쓰레드에서 확인하지 못할 수 있다. 동기화는 동기화된 메소드나 블록에 들어간 쓰레드가 같은 락의 보호 하에 수행된 모든 이전 수정의 최종 결과를 보게 해준다. 언어 명세상 long, double 외의 변수를 읽고 쓰는 동작은 원자적이다. 여러 쓰레드가 같은 변수를..
아이템 69. 예외는 진짜 예외 상황에만 사용하라 예외는 오직 예외 상황에서만 써야 하며, 일상적인 제어 흐름용으로 쓰여서는 안된다. 표즌적이고 쉽게 이해되는 관용구를 사용해야 하며, 성능 개선을 목적으로 과하게 머리를 쓴 기법은 자제한다. 잘 설계된 API 라면, 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다. 특정 상태에서만 호출할 수 있는 "상태 의존적" 메소드를 제공하는 클래스는 "상태 검사" 메소드도 함께 제공해야 한다. 예를 들어 Iterator 인터페이스의 next 와 hasNext 가 각각 상태 의존적 메소드와 상태 검사 메소드인 것이다. 이렇게 별도의 상태 검사 메소드가 있기 때문에 아래와 같은 for 문을 사용할 수 있다. (for-each 도 내부적으로 has..

아이템 57. 지역변수의 범위를 최소화하라 지역변수의 범위를 줄이는 가장 강력한 방법은 "가장 처음 쓰일 때 선언하는 것"이다. 거의 모든 지역변수는 선언과 동시에 초기화해야 한다. 초기화에 필요한 정보가 충분하지 않다면 선언을 미룬다. 메소드를 가능한 작게 유지하고 한 가지 기능에 집중하게 한다면, 지역변수의 범위를 더 좁힐 수 있다. 아이템 58. 전통적인 for 문보다는 for-each 문을 사용하라 for-each 문의 정식 명칭은 "향상된 for 문"이다. 반복자와 인덱스 변수를 사용하지 않으니 코드가 깔끔해지고 오류가 날 일이 없다. 반복 대상이 컬렉션이든 배열이든 for-each 문을 사용해도 속도는 그대로이다. 하지만 아래와 같은 상황에서는 for-each 문을 사용할 수 없다. 파괴적인 ..

아이템 49. 매개변수가 유효한지 검사하라 메소드와 생성자 대부분은 입력 매개변수의 값이 특정 조건을 만족하기를 바란다. 이런 제약은 반드시 문서화해야 하며, 메소드 몸체가 시작되기 전에 검사해야 한다. /* * (현재 값 mod m) 값을 반환한다. 이 메소드는 * 항상 음이 아닌 BigInteger 을 반환한다는 점에서 remainder 메소드와 다르다 * * @param m 계수 (양수여야 한다.) * @return 현재 값 mod m * @throws ArithmeticException m 이 0 보다 작거나 같으면 발생한다. * */ public BigInteger mod(BigInteger m) { if (m.signum() = 0 && offset = 0 && length 0) throw n..

아이템 42. 익명 클래스보다는 람다를 사용하라 예전에는 자바에서 함수 타입을 표현할 때, 함수객체라고 불리는 추상 메소드를 하나만 담은 인터페이스 (드물게는 추상클래스) 를 사용했다. 이러한 함수객체를 만드는 주요 수단은 익명클래스였다. public void test1(List words) { words.sort(new Comparator() { public int compare(String s1, String s2) { return Integer.compare(s1.length(), s2.length()); } }); } 전략패턴처럼, 함수 객체를 사용하는 과거 객체지향 디자인 패턴에는 익명클래스면 충분했다. 하지만 익명 클래스 방식은 코드가 너무 길다. 이 대신에 람다식을 사용할 수 있다. 익명 클..

아이템 34. int 상수 대신 열거 타입을 사용하라 열거타입은 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입이다. (사계절, 태양계의 행성, 카드게임 카드 등) 자바에서 열거타입을 지원하기 전에는 정수 상수를 한 묶음 선언해서 사용했었다고 한다. 이러한 방식은 타입 안전을 보장하지도 못하고, 표현력도 좋지 않다. 또 이러한 정수 열거 패턴을 사용한 프로그램은 깨지기 쉽다. 평범한 상수를 나열한 것 뿐이라 컴파일하면 그 값이 클라이언트 파일에 그대로 새겨진다. 컴파일하면 그 값이 클라이언트 파일에 그대로 새겨지며, 상수의 값이 바뀌면 클라이언트도 반드시 다시 컴파일해야 한다. 정수 상수는 문자열로 출력하기도 까다로워 디버깅할 때에도 좋지 않다고 한다. (정수 대신 문자열 상수를 ..

아이템 26. 로 타입은 사용하지 말라 클래스와 인터페이스 선언에 타입 매개변수가 사용되는 것을 제네릭 클래스 혹은 제네릭 인터페이스라고 한다. (e.g., List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E 를 받는 제네릭 인터페이스다) 제네릭 클래스, 인터페이스를 통틀어 제네릭 타입이라고 한다. 각각의 제네릭 타입은 일련의 매개변수화 타입을 정의한다. List 로 생각해보자면, List 은 원소의 타입이 String 인 리스트를 뜻하는 매개변수화 타입이다. (String 이 실제 타입 매개변수) 또, 제네릭 타입을 하나 정의하면 그에 딸린 Raw type 도 함께 정의된다. Raw type 은 제네릭 타입에서 타입 매개변수를 사용하지 않을 때를 말한다. (e.g., List) 위 로 타입을..