← SEARCHABLE ARCHIVE
Java · 2026-07-30

Java 기초부터 마스터까지 — 5화

제네릭과 컬렉션을 목적에 맞게 선택하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

Java 컬렉션은 여러 데이터를 저장하지만 자료구조마다 잘하는 일이 다르다. 제네릭을 함께 사용하면 꺼낸 값을 매번 형 변환하지 않고 타입 오류를 컴파일할 때 확인할 수 있다.

List, Set, Map

List<String> party = new ArrayList<>();
Set<Integer> unlockedIds = new HashSet<>();
Map<Integer, Item> itemById = new HashMap<>();

party.add("Rose");
unlockedIds.add(10);
itemById.put(10, new Item(10, "Potion"));

List는 순서와 중복을 허용하고, Set은 중복 없는 값의 존재 여부를 다룬다. Map은 키를 통해 값을 찾는다.

HashMap의 순서는 보장되지 않는다. 정렬이나 입력 순서가 계약이라면 그 목적에 맞는 구현을 선택해야 한다.

안전하게 검색하기

Item item = itemById.get(10);
if (item != null) {
    System.out.println(item.getName());
}

get은 키가 없으면 null을 반환한다. null 자체를 값으로 저장하는 설계를 피하면 없음과 null 값을 혼동하지 않게 된다.

제네릭 클래스

public final class Registry<T extends Identifiable> {
    private final Map<Integer, T> values = new HashMap<>();

    public void add(T value) {
        values.put(value.getId(), value);
    }

    public Optional<T> find(int id) {
        return Optional.ofNullable(values.get(id));
    }
}

T extends Identifiable은 저장할 타입이 ID를 제공해야 한다는 제약이다. Registry<Item>과 Registry<Monster>는 같은 규칙을 재사용하지만 값이 서로 섞이지 않는다.

구현보다 인터페이스에 의존하기

필드와 매개변수 타입을 List나 Map 인터페이스로 두면 필요한 동작만 계약에 남는다. 하지만 성능 특성이 중요하다면 실제 구현이 ArrayList인지 LinkedList인지도 알고 있어야 한다.

컬렉션 선택은 데이터 개수만의 문제가 아니다. 순서, 중복, 검색 키, 변경 빈도라는 사용 목적을 먼저 정해야 한다.