Item27. 비검사 경고를 제거하라

@SuppressWarnings

compiler 경고를 제거할수는 없지만 타입 안전하다고 확신할 수 있다면 @SuppressWarning(“unchecked”) annotation을 달아 경고를 숨길 수 있다, 단 rumtime에 ClassCastException이 발생하지 않도록 타입 안전함을 검증해야 한다.

Read more

Item26. Generic Raw Type은 사용을 자제하라

Generic Type

클래스와 인터페이스 선언에 타입 매개변수(type parameter)가 쓰이면 이를 generic class 또는 generic interface라 한다. 이 두 개를 통칭해서 Generic type이라고 부른다.

1
public class GenericExample<T>{} // T : 타입 매개변수 

각각의 generic type은 매개변수화 타입 (parameterized type)을 정의한다. 매개변수화타입은 <> 괄호 안에 실제 타입을 명시함으로서 정의가 가능하다.

1
GenericExample<String> stringGenericExample = new GenericExample<>();

raw tye은 generic type을 하나 정의하면 함께 정의되는데, generic type에서 타입 매개변수를 전혀 사용하지 않았을떄를 말한다. , raw type이 generic type을 하나 정의할떄마다 같이 생성되는 이유는 기존 java code와 호환성 문제떄문이다.

1
GenericExample rawTypeGeneric = new GenericExample();
Read more

Item25. top level class는 한 파일에 하나만 담으라

소스 파일 하나당 top-level class를 여러개 선언해도 compile error는 나지 않는다,

1
2
3
4
5
6
7
8
9
// Utensil.java 
class Utensil {

static final String NAME = "pan";
}

class Dessert{
static final String NAME = "cake";
}
1
2
3
4
5
6
7
8
class Dessert {

static final String NAME = "pie";
}

class Utensil {
static final String NAME = "pot";
}

위와 같이 하나의 java file에 여러개의 class가 들어있는 경우 문제가 생길수도 있다.

Read more

Item23. 태그 달린 class보다는 class 계층 구조를 활용하자

태그 달린 class

헌재 표현하는 의미를 태그 값으로 알려주는 class 는 아래와 같이 class 계층구조를 사용하지 않고, 한 class내에 태그 필드를 가지는 class를 말한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Figure {

enum Shape {RECTANGLE,CIRCLE};
// 현재 모양
final Shape shape;

// RECTANGLE일떄만 쓰이는 필드
double length;
double width;

// CIRCLE일떄만 쓰이는 필드
double radius;

// CIRCLE용 생성자
public Figure(double radius) {
this.shape = Shape.CIRCLE;
this.radius = radius;
}

// RECTANGLE용 생성자
public Figure(double length, double width) {
this.shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
}

double area(){
switch (shape){
case RECTANGLE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError(shape);
}
}
}
  • 태그 달린 class의 단점

  1. 태그 필드를 가지고, 분기처리 (swith,if-else)를 하기 때문에 코드 가독성이 떨어지고, 계층형 구조로 가져갔을때 불필요한 코드들이 생긴다.

  2. 태그 값마다 필요한 필드가 다른데, 이를 모두 하나의 class에 보관함으로, 객체를 생성하였을떄 사용되지 않는 필드 (메모리 낭비) 도 같이 초기화 된다.

  3. 변경에 열려있다, 태그 값 추가시마다 분기로직을 수정해야 한다.

  4. 인스턴스 타입을 보고 현재 타입이 나타내는 의미를 알 수가 없다.

Read more

Item22. 인터페이스는 타입을 정의하는 용도로만 사용하라

인터페이스의 사용 용도

인터페이스는 자신을 구현한 class의 instance를 참조할 수 있는 타입 역할을 한다.

즉 class가 어떤 인터페이스를 구현한다는 것은 자신의 인터페이스로 무엇을 할수 있을 지 client에게 얘기해주는 것이며, 인터페이스는 오직 이 용도로만 사용해야 한다.

Read more

Item20. 추상 클래스보다는 인터페이스를 우선하라

추상 class

추상 class와 인터페이스의 가장 큰 차이점은 추상 class가 정의한 type을 구현하는 class는 반드시 추상 class의 하위 타입이 되야한다는 점이다.

java는 단일 상속만 지원함으로, 추상 class 방식은 새로운 타입을 정의하는데 제약을 갖게 된다. 반면 인터페이스의 경우는 어떤 class를 상속했더라도 같은 type으로 취급된다

기존 class에 새로운 인터페이스를 구현해넣는것은 쉬우나, 새로운 추상 class를 넣기는 힘들다.
두 class가 동일한 추상 class 를 확장하려면 그 추상 class는 계층구조상 두 class의 공통조상이여야 한다.

Read more

Item19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

상속용 클래스의 문서화

  • 상속용 클래스는 overriding할 수 있는 method들을 내부적으로 어떻게 이용하는 지 문서로 남겨야 한다.
  • 클래스의 API로 공개된 method에서 클래스 자신의 또 다른 method를 호출할 수도 있는데, 이 method가 overriding이 가능하다면 method의 API 설명에 적어두어야 한다.
  • 어떤순서로 호출되는지, 호출 결과가 이어지는 처리에 어떤 영향을 줄 수 있는지도 문서화해야한다.

문서화 예시 : https://docs.oracle.com/javase/7/docs/api/java/util/AbstractCollection.html

API 문서의 method설명 끝에서 종종 ‘This Implementation’ ~ 로 시작하는 절을 볼 수 있는데 이 부분이 method의 내부 동작 방식을 설명하는 곳이다.

클래스를 안전하게 상속할 수 있도록 하려면, 내부 구현 방식에 대해 설명해주어야 한다.

( Java method 주석에 @implSpec tag를 붙여주면 자바독 도구가 생성해준다. )

Read more

Item18. 상속보다는 Composition을 사용해라

상속의 단점

  • 상속은 캡슐화를 꺠트린다.

상위 class 내부 구현 변경에 따라 하위 class가 영향을 받을 수도 있다. 상위 class가 확장을 충분히 고려해두고 설계되지 않으면 하위 class는 상위 class의 변화맞추어 수정되야 한다.

Read more