1. 기존 instanceof의 문제
잠깐 과거를 돌아봅시다. Java 16 이전에는 객체의 타입을 확인한 뒤 그 타입으로 사용하려면, instanceof 검사와 명시적 캐스팅을 함께 쓰는 장황한 패턴을 매번 작성해야 했습니다:
Object obj = ...; // 어떤 객체
if (obj instanceof String) {
String s = (String) obj;
System.out.println("문자열 길이: " + s.length());
}
지루하지만 자주 나오는 패턴
이 패턴은 매우 자주 등장합니다 — 이벤트 핸들러, 이기종 컬렉션 처리, 상속이 있는 비즈니스 로직 등등.
왜 불편한가
- 코드 중복 — instanceof와 캐스팅 양쪽에 타입을 두 번 적어야 합니다.
- 오류 위험 — 잘못된 타입으로 캐스팅해 ClassCastException을 일으키기 쉽습니다.
- “노이즈” 코드 — 특히 다중 검사일 때 가독성을 해칩니다.
2. Pattern Matching for instanceof: 새로운 문법
Java 16에서는 instanceof에 패턴 매칭이 추가되었습니다. 이제 타입을 확인함과 동시에 해당 타입의 변수를 선언하고, 그 변수는 if 블록 내부에서 바로 사용할 수 있습니다.
새로운 문법
if (obj instanceof String s) {
// s는 이미 문자열!
System.out.println("문자열 길이: " + s.length());
}
- instanceof의 타입 뒤에 새 변수 이름을 적습니다: String s.
- 변수는 조건이 참인 블록 내부에서만 볼 수 있습니다.
- (String) 같은 캐스팅을 쓸 필요가 없습니다 — 컴파일러가 보장합니다.
무슨 일이 일어나나? 컴파일러가 타입을 검사하고, 맞으면 필요한 타입의 변수를 “열어” 줍니다. 아니면 블록이 그냥 실행되지 않습니다.
실제 코드에서는 이렇게 보입니다
Object obj = "안녕, Java 16+!";
if (obj instanceof String s) {
System.out.println("대문자: " + s.toUpperCase());
} else {
System.out.println("문자열이 아닙니다!");
}
3. 안전성과 가독성: 왜 좋은가
ClassCastException 오류를 제거
Object obj = 123;
// String s = (String) obj; // 붐! 예외.
패턴 매칭에서는 타입 확인이 성공할 때만 변수가 생성되므로 — “잘못된” 캐스팅 자체가 없습니다.
코드는 더 짧고 이해하기 쉬워집니다
두 줄이 한 줄이 됩니다. “노이즈” 코드가 줄면 읽기와 유지보수가 쉬워집니다.
예: 서로 다른 타입 처리
public static void printInfo(Object obj) {
if (obj instanceof String s) {
System.out.println("문자열 길이 " + s.length());
} else if (obj instanceof Integer i) {
System.out.println("정수: " + (i + 1));
} else {
System.out.println("알 수 없는 타입: " + obj);
}
}
4. 사용 예와 요령
여러 타입 검사
Object value = ...;
if (value instanceof String s) {
System.out.println("문자열입니다: " + s);
} else if (value instanceof Number n) {
System.out.println("숫자입니다: " + n);
} else {
System.out.println("다른 것: " + value);
}
null과 함께 사용하기
객체가 null이면 instanceof는 항상 false를 반환합니다 — NPE는 없지만 블록도 실행되지 않습니다.
Object obj = null;
if (obj instanceof String s) {
// obj == null이면 이 블록은 절대 실행되지 않습니다
System.out.println("문자열: " + s);
} else {
System.out.println("obj는 null 이거나 문자열이 아닙니다");
}
상속과 함께 하는 pattern matching
class Animal {}
class Dog extends Animal {
void bark() { System.out.println("멍!"); }
}
Animal a = new Dog();
if (a instanceof Dog d) {
d.bark(); // 캐스팅 없이 Dog 메서드를 호출할 수 있습니다!
}
검사 순서는 중요합니다: 더 구체적인 타입에서 더 일반적인 타입 순으로 진행하세요. 그렇지 않으면 “좁은” 검사들이 작동하지 않을 수 있습니다.
비교: 기존 방식 vs 새 방식
| 기존 방식 | 새 방식 (pattern matching) |
|---|---|
|
|
5. instanceof용 pattern matching의 제약
- 변수 스코프. 패턴으로 생성된 변수는 조건이 참인 그 분기 안에서만 보입니다.
if (obj instanceof String s) {
System.out.println(s); // s 사용 가능
}
// System.out.println(s); // 오류! 여기서는 s가 보이지 않습니다
- 하나의 조건식에서 서로 다른 타입의 변수를 여러 개 선언할 수 없습니다.
// 컴파일 오류:
if (obj instanceof String s || obj instanceof Integer i) {
// ...
}
- Java 16+ 필요. 더 오래된 JDK 버전에서는 새 문법이 지원되지 않습니다.
6. 실전 예제 (간단한 애플리케이션 기반)
여러 타입의 작업이 있는 간단한 Task Manager가 있다고 가정해 봅시다.
클래스
class Task {
String title;
public Task(String title) { this.title = title; }
}
class BugTask extends Task {
int severity;
public BugTask(String title, int severity) {
super(title);
this.severity = severity;
}
}
class FeatureTask extends Task {
String feature;
public FeatureTask(String title, String feature) {
super(title);
this.feature = feature;
}
}
pattern matching으로 처리하기
public static void processTask(Task t) {
if (t instanceof BugTask bug) {
System.out.println("버그: " + bug.title + ", 심각도: " + bug.severity);
} else if (t instanceof FeatureTask feature) {
System.out.println("기능: " + feature.title + ", 모듈: " + feature.feature);
} else if (t instanceof Task task) {
System.out.println("일반 작업: " + task.title);
}
}
7. 유용한 팁
표: instanceof용 pattern matching — 장점과 단점
| 장점 | 단점/제약 |
|---|---|
| 코드가 줄고 가독성이 높아짐 | Java 16+ 필요 |
| ClassCastException 위험 없음 | 변수는 if 블록 안에서만 보임 |
| 컴파일러 수준의 타입 안전성 | 하나의 조건에서 여러 타입에는 동작하지 않음 |
| 상속 처리에 유리 | 오래된 IDE나 빌드에서는 지원되지 않을 수 있음 |
| 어떤 클래스에도 적용 가능 |
시각적 다이어그램: instanceof용 pattern matching이 동작하는 방식
+---------------------------+
| Object obj |
+---------------------------+
|
v
if (obj instanceof Type t)
|
예 아니오
(true) (false)
| |
v v
t 사용 가능 t 존재하지 않음
(코드) (접근 불가)
8. instanceof용 pattern matching 사용 시 흔한 실수
오류 №1: if 블록 밖에서 변수를 사용하려는 시도. 패턴에서 변수를 선언하고 블록을 벗어나면 — 그 변수는 더 이상 존재하지 않습니다. 컴파일러는 정당하게 항의합니다: “s가 누구죠?”
오류 №2: instanceof가 null에도 동작할 것이라 기대. 객체가 null이면 instanceof 조건은 항상 거짓이며, 변수는 생성되지 않습니다. 필요하면 null을 별도로 처리하세요.
오류 №3: 오래된 JDK/IDE에서 새 문법을 사용. Java 11 이하에서는 instanceof에 대한 패턴 매칭이 제공되지 않습니다 — 문법 오류가 납니다. JDK 버전을 확인하세요.
오류 №4: 스코프 혼동. 패턴으로 생성된 변수는 조건이 참인 그 분기에서만 접근할 수 있습니다. 그 밖에서는 존재하지 않습니다.
오류 №5: 여러 타입을 동시에 지원한다고 기대. 하나의 조건식에서 서로 다른 타입의 변수를 두 개 동시에 선언할 수 없습니다: if (obj instanceof String s || obj instanceof Integer i) — 이렇게는 안 됩니다. 각 타입마다 별도의 검사를 사용하세요.
GO TO FULL VERSION