본문 바로가기

책/Effective Java

(11)
직렬화 자바 직렬화의 대안을 찾으라 - 직렬화 위험을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는 것이다. - 차선책은 신뢰할 수 없는 데이터는 절대 역직렬화하지 않는 것이다. - 새로운 시스템에서 자바 직렬화를 써야 할 이유는 전혀 없다. - 객체 역직렬화 필터링(java.io.ObjectInputFilter)를 사용하자. (블랙리스트 보다는 화이트리스트 방식을 추천한다.) Serializable을 구현할지는 신중히 결정하라 - Serialiazable을 구현하면 릴리스한 뒤에는 수정하기 어렵다. - 버그와 보안 구멍이 생길 위험이 높아진다. - 해당 클래스의 신버전을 릴리스할 때 테스트할 것이 많아진다. - Serializable 구현 여부는 가볍게 결정할 사안이 아니다.- 상속용으로 설계된 클래스..
동시성 공유 중인 가변 데이터는 동기화해 사용하라 - 동기화는 배타적 실행뿐 아니라 스레드 사이의 안정적인 통신에 꼭 필요하다. - Thread.stop은 사용하지 말자. - 가변 데이터는 단일 스레드에서만 쓰도록 하자. - 쓰기와 읽기 모두가 동기화되지 않으면 동작을 보장하지 않는다.- 동기화하지 않으면 한스레드가 수행한 변경을 다른 스레드가 보지 못할 수도 있다.- 공유되는 가변 데이터를 동기화하는데 실패하면 응답 불가 상태에 빠지거나 안전 실패로 이어질 수 있다.(디버깅 난이도가 가장 높은 문제에 속한다.) - 배타적 실행은 필요 없고 스레드끼리의 통신만 필요하다면 volatile 한정자만으로 동기화할 수 있다. 과도한 동기화는 피하라 - 응답 불가와 안전 실패를 피하려면 동기화 메서드나 동기화 블록 안에..
예외 예외는 진짜 예외 상황에만 사용하라 - 예외는 오직 예외 상황에서만 써야 한다. 절대로 일상적인 제어 흐름용으로 쓰여선 안 된다. - 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다. 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라. - 호출하는 쪽에서 복구하리라 여겨지는 상황이라면 검사 예외를 사용하자. - 프로그래밍 오류를 나타낼 때는 런타임 예외를 사용하자. - 구현하는 비검사 throwable은 모두 RuntimeException의 하위 클래스여야 한다. (Error는 상속하지 말아야 할 뿐 아니라, throw 문으로 직접 던지는 일도 없어야 한다.) - 검사 예외도 아니고 런타임 예외도 아닌 throwable은 정의하..
일반적인 프로그래밍 원칙 지역변수의 범위를 최소화하라 - 가장 처음 쓰일 때 선언하자. - 선언과 동시에 초기화해야 한다. - 컬렉션이나 배열 순회for (Element e : c) {...} - 반복자가 필요할 때for (Iterator i = c.iterator(); i.hasNext(); ) {...} - 메서드를 작게 유지하고 한 가지 기능에 집중해라. 전통적인 for문 보다는 for-each문을 사용하라 - for-each문을 사용할 수 없는 상황- 파괴적인 필터링 : 컬렉션을 순회하면서 선택된 원소를 제거해야 하는 경우 (자바 8에서는 Collection의 removeIf 메서드를 사용한다.)- 변형 : 리스트나 배열을 순회하면서 그 원소의 값 일부 혹은 전체를 교체해야 하는 경우- 병렬 반복 : 여러 컬렉션을 병렬로..
메서드 매개변수가 유효한지 검사하라 - 메서드나 생성자를 작성할 때 매개변수들에 어떤 제약이 있을지 생각하고 메서드 코드 시작 부분에서 명시적으로 검사해야 한다. - public과 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 문서화해야 한다. - 자바 7에 추가된 java.util.Objects.requireNonNull 메서드는 유연하고 사용하기도 편하니, 더 이상 null 검사를 수동으로 하지 않아도 된다.this.stratergy = Objects.requireNonNull(strategy, "전략"); 적시에 방어적 복사본을 만들라 - 클라이언트에서 불변식을 깨뜨리려고 한다고 가정하고 방어적으로 프로그래밍해야 한다. - Date는 낡은 API이니 새로운 코드를 작성할 때는 더 이상..
람다와 스트림 익명 클래스보다는 람다를 사용하라 - 익명 클래스Collection.sort(words, new Compareator() {public int compare(String s1, String s2) {return Integer.compare(s1.length(), s2.length());}} - 람다식을 함수 객체로 사용Collection.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length())); - 타입을 명시해야 코드가 더 명확할 때를 제외하고는, 람다의 모든 매개변수 타입은 생략하자. - 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다. - 람다를 직..
열거 타입과 애너테이션 int 상수 대신 열거 타입을 사용하라 - 컴파일 타입 안정성을 제공한다. - 더 읽기 쉽고 안전하다. - 각 상수를 특정 데이터와 연결지으려면 생성자에서 데이터를 받아 인스턴스 필드에 저장하면 된다. - 상수 일부가 같은 동작을 공유한다면 전략 열거 타입 패턴을 사용하자. ordinal 메서드 대신 인스턴스 필드를 사용하라 - ordinal 메서드는 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환한다. - 열거 타입 상수에 연결된 값은 ordinal 메서드로 얻지 말고 인스턴스 필드에 저장하자 - ordinal()의 값을 사용public enum Ensemble {SOLO, DUET, TRIO; public int numberOfMusicians() { return ordinal() + 1; }..
제네릭 로 타입은 사용하지 말라 - 안 좋은 예final Collection stamps = ...;for (Iterator i = stamps.iterator(); i.hasNext();) {Stamp stamp = (Stamp) i.next();...;} - 좋은 예final Collection stamps = ...;for (Stamp i : stamps) {Stamp stamp = i;...;} 비검사 경고를 제거하라 - 할 수 있는 한 모든 비검사 경고를 제거하라. - 경고를 제거할 수는 없지만 타입 안전하다고 확신할 수 있다면 @SuppressWarnings("unchecked") 애너테이션을 달아 경고를 숨기자. (가능한 좁은 범위에 사용하고, 경고를 무시해도 되는 안전한 이유를 항상 주석으로 남겨..