전체 글 194

[Effective Java] Item 27. 비검사 경고를 제거하라

[Effective Java] Item 27. 비검사 경고를 제거하라 핵심정리 비검사 경고는 중요하니 무시하지 말자. 모든 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있는 잠재적 가능성을 뜻하니 최선을 다해 제거하라. 경고를 없앨 방법을 찾지 못하겠다면, 그 코드가 타입 안전함을 증명하고 가능한 한 범위를 좁혀 @SuppressWarning("unchecked") 애너테이션으로 경고를 숨겨라. 그런 다음 경고를 숨기기로 한 근거를 주석으로 남겨라. 제네릭을 사용하기 시작하면 수많은 컴파일러 경고를 보게 될 것이다. 비검사 형변환 경고, 비검사 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환 경고 등이다. 제네릭에 익숙해질수록 마주치는 경고 수는 줄겠지만 ..

[Effective Java] Item 26. 로 타입은 사용하지 말라

[Effective Java] Item 26. 로 타입은 사용하지 말라 핵심정리 로 타입을 사용하면 런타임에 예외가 일어날 수 있으니 사용하면 안 된다. 로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다. 빠르게 훑어보자면, Set은 어떤 타입의 객체도 저장할 수 있는 매개변수화 타입이고, Set은 모든 종의 타입 객체만 저장할 수 있는 와일드카드 타입이다. 그리고 이들의 로 타입인 Set은 제네릭 타입 시스템에 속하지 않는다. Set와 Set는 안전하지만, 로 타입인 Set은 안전하지 않다. 제네릭 타입 (generic type) 클래스와 인터페이스 선언에 타입 매개변수(type parameter)가 쓰인 것 List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받는다...

[Effective Java] Item 25. 톱레벨 클래스는 한 파일에 하나만 담으라

[Effective Java] Item 25. 톱레벨 클래스는 한 파일에 하나만 담으라 소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위다. 이렇게 하면 한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문이다. 구체적인 예를 보자. 다음 소스 파일은 Main 클래스 하나를 담고 있고, Main 클래스는 다른 톱레벨 클래스 2개(Utensil과 Dessert)를 참조한다. public class Main { public static void main(String[] args) { System.out.println(Utensil.N..

[Effective Java] Item 24. 멤버 클래스는 되도록 static으로 만들라

[Effective Java] Item 24. 멤버 클래스는 되도록 static으로 만들라 중첩 클래스(nested class)란? 중첩 클래스(nested class)란? 다른 클래스 안에 정의된 클래스 자신을 감싼 바깥 클래스에서만 쓰여야 한다. 중첩 클래스의 종류 정적 멤버 클래스 (비정적) 멤버 클래스 익명 클래스 지역 클래스 중첩 클래스를 언제 그리고 왜 사용해야 할까? 정적 멤버 클래스 특징 class 내부에서 static으로 선언된 클래스 다른 클래스 안에 선언된다. 바깥 클래스의 private 멤버에도 접근할 수 있다 다른 점은 일반 클래스와 동일 public class Developer { private String name; private String year; public static..

[Effective Java] Item 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라

[Effective Java] Item 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 본 적이 있을 것이다. 다음 코드는 원과 사각형을 표현할 수 있는 클래스다. 핵심 정리 태그 달린 클래스를 써야 하는 상황은 거의 없다. 새로운 클래스를 작성하는 데 태그 필드가 등장한다면 태그를 없애고 계층구조로 대체하는 방식을 생각해보자. 기존 클래스가 태그 필드를 사용하고 있다면 계층구조로 리팩터링하는 걸 고민해보자. 태그 달린 클래스 - 클래스 계층구조보다 훨씬 나쁘다! class Figure { enum Shape { RECTANGLE, CIRCLE }; // 태그 필드 - 현재 모양을 나타낸다. fi..

[Effective Java] Item 22. 인터페이스는 타입을 정의하는 용도로만 사용하라

[Effective Java] Item 22. 인터페이스는 타입을 정의하는 용도로만 사용하라 핵심 정리 인터페이스는 타입을 정의하는 용도로만 사용해야 한다. 상수 공개용 수단으로 사용하지는 말자. 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 달리 말해, 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. 이 지침에 맞지 않는 예로 소위 상수 인터페이스라는 것이 있다. 상수 인터페이스란 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 그리고 이 상수들을 사용하려는 클래스에서는 정규화된 이름(qualified name)..

[Effective Java] Item 21. 인터페이스는 구현하는 쪽을 생각해 설계하라

[Effective Java] Item 21. 인터페이스는 구현하는 쪽을 생각해 설계하라 자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었다. 인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데, 추가한 메서드가 우연히 기존 구현체에 이미 존재할 가능성은 아주 낮기 때문이다. 자바 8에 와서 기존 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드를 소개했지만, 위험이 완전히 사라진 것은 아니다. 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 이처럼 자바에도 기존 인터페이스에 메서드를 추가하는 길이 열렸지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. 자바 7까지..

[Effective Java] Item 20. 추상 클래스보다는 인터페이스를 우선하라.

[Effective Java] Item 20. 추상 클래스보다는 인터페이스를 우선하라. 핵심 정리 일반적으로 다중 구현용 타입으로는 인터페이스가 가장 적합하다. 복잡한 인터페이스라면 구현하는 수고를 덜어주는 골격 구현을 함께 제공하는 방법을 꼭 고려해보자. 골격 구현은 '가능한 한' 인터페이스의 디폴트 메서드로 제공하여 그 인터페이스를 구현한 모든 곳에서 활용하도록 하는 것이 좋다. '가능한 한'이라고 한 이유는, 인터페이스에 걸려 있는 구현상의 제약 때문에 골격 구현을 추상 클래스로 제공하는 경우가 더 흔하기 때문이다. 자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스, 이렇게 두 가지다. 자바 8부터 인터페이스도 디폴트 메서드 (default method)를 제공할 수 있게 되어 이제는 ..

[Effective Java] Item 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라.

[Effective Java] Item 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라. 핵심 정리 상속용 클래스 설계하기 1. 클래스 내부에서 스스로 어떻게 사용하는지 (자기 사용 패턴) 모두 문서로 남겨야 한다. 2. 문서화한 것은 그 클래스가 쓰이는 한 반드시 지켜야 한다. (그러지 않으면 그 내부 구현 방식을 믿고 활용하던 하위 클래스를 오동작하게 만들 수 있다.) 3. 다른 이가 효율 좋은 하위 클래스를 만들 수 있도록 일부 메서드를 protected로 제공해야 할 수도 있다. 4. 클래스를 확장해야 할 명확한 이유가 떠오르지 않으면 상속을 금지하자 5. 상속을 금지하려면 클래스를 final로 선언하거나 생성자 모두를 외부에서 접근할 수 없도록 만들면 된다. 상속용 메..

[Effective Java] Item 18. 상속보다는 컴포지션을 사용하라

[Effective Java] Item 18. 상속보다는 컴포지션을 사용하라 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선은 아니다. 잘못 사용하면 오류를 내기 쉬운 소프트웨어를 만들게 된다. 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 안에서라면 상속도 안전한 방법이다. 확장할 목적으로 설계되었고 문서화도 잘 된 클래스도 마찬가지다. 하지만 일반적인 구체 클래스를 패키지 경계를 넘어, 즉 다른 패키지의 구체 클래스를 상속하는 일을 위험하다. 이 책에서 논하는 상속은 클래스가 다른 클래스를 확장하는 구현 상속을 의미한다. 인터페이스 상속과는 무관하다. 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 다르게 말하면, 상위 클래스가 어떻게 구현되느냐에 따라 하위 클래스의 동작에..