[자바] 9. var : 타입 추론과 불변 컬렉션 팩토리 (Java 9~10)

자바 버전 여행 9편 - 타입 추론과 불변 컬렉션 팩토리

작성자

카테고리:

* 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

(자바 버전 여행 ⑨)

자바 10은 6개월 버전이라 짧게 지나갔지만, 매일 타이핑을 줄여주는 기능 하나를 남겼다. var다. 여기에 자바 9가 준 불변 컬렉션 팩토리까지, 이번 편은 ‘작지만 매일 쓰는’ 것들을 모은다.

var — 타입을 컴파일러에게 맡긴다

좌변 타입과 우변 타입을 두 번 적는 게 늘 아까웠다. var는 지역변수에 한해 우변을 보고 타입을 추론한다. 주의할 건, 동적 타입이 아니라 컴파일 타임에 타입이 고정된다는 것. 자바스크립트의 var와는 완전히 다르다.

// Before
Map<String, List<Integer>> scores = new HashMap<String, List<Integer>>();

// After — 우변에 타입이 다 있으니 좌변은 var
var scores = new HashMap<String, List<Integer>>();
var name = "cozmo";       // String
var count = 10;            // int

Java 9 — 불변 컬렉션을 한 줄로

리스트 하나 만들자고 new ArrayList 후 add를 반복하던 게, 자바 9부터 List.of(...) 한 줄이면 된다. 대신 이렇게 만든 컬렉션은 불변이라 나중에 못 바꾼다.

var days = List.of("월", "화", "수");
var caps = Map.of("KR", "서울", "JP", "도쿄");

days.add("목");   // 실행 시 UnsupportedOperationException!

이 불변성이 실수를 막아준다. “읽기 전용”이어야 할 상수를 진짜 읽기 전용으로 만들 수 있다.

직접 해보기 — var 리팩터와 불변의 벽 체험

타입 추론과 불변 컬렉션을 손으로 확인해 보자.

  1. 길게 선언된 지역변수 두어 개를 var로 바꿔 컴파일이 그대로 되는지 본다.
  2. List.of(1,2,3)를 만들고 add(4)를 호출해 예외를 확인한다.
  3. 바꿔야 한다면 new ArrayList<>(List.of(1,2,3))로 감싸 가변 사본을 만든다.
var nums = List.of(1, 2, 3);
System.out.println(nums.getClass().getSimpleName());
try {
    nums.add(4);
} catch (UnsupportedOperationException e) {
    System.out.println("불변이라 못 바꿈: " + e.getClass().getSimpleName());
}
var mutable = new ArrayList<>(nums);   // 가변 사본
mutable.add(4);
System.out.println(mutable);

실행해 보면 이렇게 나온다.

ListN
불변이라 못 바꿈: UnsupportedOperationException
[1, 2, 3, 4]

여기서 조금씩 바꿔 보자.

  • Map.of로 맵을 만들고 put을 시도해 같은 예외가 나는지 본다.
  • var x; 처럼 우변 없이 선언하면 왜 컴파일 에러인지 생각해 본다(추론할 근거가 없다).

한 걸음 더 — List.copyOf(someList)로 기존 리스트의 불변 사본을 만드는 것도 확인해 보자.

✅ 확인 — var가 컴파일 타임 타입 추론(동적 타입 아님)이라는 것과 List.of가 불변이라는 걸 설명할 수 있으면 통과다.

var가 빛나는 곳 / 못 쓰는 곳

var의 가치는 긴 제네릭 타입에서 가장 크다. 좌우로 두 번 적던 걸 한 번으로 줄인다. 다만 쓸 수 없는 자리도 분명하다.

쓰기 좋은 곳쓸 수 없는 곳
var m = new HashMap<String, List<Order>>();필드·메서드 파라미터·반환 타입(지역변수 전용)
for (var e : entries) …초기화 없는 선언(var x;)
긴 타입의 지역변수우변이 null·람다·배열 초기화{}만인 경우

가독성 — 타입이 안 보이면 남겨라

우변이 타입을 분명히 말해주면(new ArrayList<>()) var가 깔끔하다. 하지만 var x = getData();처럼 우변만 봐선 타입을 모를 때는 읽는 사람이 헷갈린다. 이럴 땐 타입을 명시하거나 변수명으로 힌트를 준다. ‘var는 중복 제거용이지 타입 감추기용이 아니다‘가 핵심 원칙이다.

불변 컬렉션 팩토리의 함정

자바 9의 List.of·Map.of·Set.of는 진짜 불변이다. add·put을 하면 UnsupportedOperationException이 터진다. 또 List.of는 null 원소를 허용하지 않는다(NPE). 옛 Arrays.asList가 크기만 고정이고 set은 되던 것과 달리, List.of는 아예 다 막힌다 — 이 차이를 모르면 런타임에 놀란다. 수정할 컬렉션이 필요하면 new ArrayList<>(List.of(...))로 감싼다. 함정 하나 더 — Map.of("a",1,"a",2)처럼 키가 겹치면 조용히 덮어쓰는 게 아니라 IllegalArgumentException이 즉시 터진다. 설정값을 코드로 옮기다 흔히 만나는 예외라, 만드는 시점에 키 중복을 잡아주는 안전장치라고 이해하면 된다.

이제 자바 11 LTS로 들어간다. 다음 편은 그동안 서드파티 라이브러리에 의존하던 일을 표준으로 끌어온 표준 HttpClient와 문자열 편의 메서드다.

자주 묻는 질문 (FAQ)

var는 자바스크립트 var처럼 동적 타입인가요?

아닙니다. 컴파일 타임에 타입이 고정되는 타입 추론입니다. 한 번 정해지면 다른 타입을 넣을 수 없습니다.

var를 어디에나 써도 되나요?

지역변수에만 됩니다. 필드·파라미터·반환 타입엔 못 쓰고, 우변만 봐도 타입이 분명할 때 쓰는 게 좋습니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다