Home [Effective Java] Generic에 대하여…
Post
Cancel

[Effective Java] Generic에 대하여…

최근 JDBC를 이용해 정말 간단한 이커머스 CRUD를 개발하면서 팀원들과 제네릭 사용에 대해 많이 고민했다. 제네릭을 따로 정의해서 사용해본 경험이 거의 없었기 때문에 정확히 왜 사용하고 어떤 점에서 타입 안정성이 보장된다고 하는지 알고 싶어 Effective Java에 제네릭 부분을 읽고 정리하게 되었다.

Generic이란?

Java 5 부터 사용할 수 있는 generic은 컬렉션이 담을 수 있는 타입을 컴파일러에 알려준다. 꺽쇠 괄호에 클래스 타입을 명시하는 형태로 사용하며 타입 안정성을 보장하고 확장성을 높여준다.

raw 타입은 사용하지 마라

Raw type은 List<E>에서 보면 List가 raw type이다. Raw type은 타입 선언에서 제네릭 타입 정보가 전부 지워진 것처럼 동작하게 된다. Raw type을 사용하면 개발자가 실수로 다른 타입을 넣어도 컴파일 시점에서는 알 수 없게 된다. 개발 시에는 컴파일 시점에 오류를 알 수 있는 것이 가장 좋다.

1
2
3
4
public class GenericPractice {
    List raw = new ArrayList(); // Raw use of parameterized class 'ArrayList'
    List<String> generic = new ArrayList<>();
}

Raw 타입을 사용하게 되면 intellij에서 raw 타입 사용이라는 경고를 알려준다. 제네릭을 사용하여 List가 어떤 타입으로 구성되어야 하는지 정의해준다.

제네릭 타입, 메서드로 만들어 사용하라

1
2
3
4
5
6
7
8
9
public class GenericStack {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();
        for (String arg :
                args) {
            stack.push(arg);
        }
    }
}

제네릭 스택을 사용한 코드이다. String 타입을 가지는 스택으로 정의한 것처럼, 타입 매개변수에 다양한 타입을 사용할 수 있다. Object, int[], List 과 같이 reference 타입은 모두 가능하다. 하지만 int와 double 같은 primitive 타입은 사용 불가하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BaseEntity<ID extends Number> {

    ID userId;

    public BaseEntity(ID userId) {
        this.userId = userId;
    }

    public static void main(String[] args) {
        long a = 2L;
        BaseEntity<Long> baseEntity = new BaseEntity<>(a);
        System.out.println(baseEntity.userId);
    }
}

위와 같이 BaseEntity의 ID를 정의하는데 Number 타입의 ID를 사용해야 한다. Number 타입에는 Integer, Long, Double 등을 사용할 수 있다.

1
BaseEntity baseEntity = new BaseEntity(a);

pic

위와 같이 BaseEntity를 정의하게 되면 경고가 뜨게 되며 raw 타입을 제네릭하게 변경하도록 제안을 한다. BaseEntity 과 같이 타입을 정하면 규약을 정할 수 있다.

클래스 설계 시 형변환 없이 사용할 수 있도록 제네릭을 도입하는 것이 타입 안정성을 높일 수 있는 방법이다.

재귀적 타입 한정을 이용해 상호 비교를 표현한다

1
public static <E extends Comparable<E>> E max(Collection<E> c)

위 코드는 모든 E 타입은 자신과 비교할 수 있다라고 이해할 수 있다. 제네릭 메서드를 사용하면 입력 매개변수와 반환값을 명시적으로 형변환해야 하는 메서드보다 안전하고 사용하기 쉽다.

타입과 메서드는 형변환 없이 사용할 수 있는 것이 좋으며, 제네릭을 사용하면 이것을 해결할 수 있다.

This post is licensed under CC BY 4.0 by the author.

[Effective Java] 싱글턴과 빌더 패턴

AOP with java