자바 개발을 하다 보면 특정 타입을 확인하고 그 타입의 메서드를 쓰기 위해 지겹게 반복하는 코드가 있습니다. 바로 instanceof로 확인하고 다시 (Casting)을 하는 과정이죠.
오늘은 JDK 16부터 정식 도입되어 우리 코드를 훨씬 깔끔하게 만들어준 패턴 매칭(Pattern Matching) 기능과, 은근히 헷갈리는 스코프(Scope) 규칙을 정리해 보겠습니다.
1. 우리가 그동안 작성하던 방식 (AS-IS)
기존에는 객체의 타입을 확인한 뒤, 다시 명시적으로 캐스팅을 해줘야 했습니다.
if (obj instanceof String) {
String str = (String) obj; // 아... 이 코드를 또 써야 하나요?
System.out.println(str.toUpperCase());
}
이 방식은 **타입 체크(instanceof)**와 **형변환((String))**이 분리되어 있어 코드가 중복되고 가독성이 떨어집니다.
2. JDK 16+ 패턴 매칭의 도입 (TO-BE)
이제는 타입을 확인하는 동시에 **패턴 변수(Pattern Variable)**를 선언하여 바로 사용할 수 있습니다.
// 타입 확인과 동시에 변수 선언(str)까지!
if (obj instanceof String str) { <------ 차이
System.out.println(str.toUpperCase());
}
이 한 줄의 코드로 타입 체크와 캐스팅이 한 번에 해결됩니다. 훨씬 직관적이죠?
3. 스코프 Flow Scoping 이해하기
패턴 변수의 스코프는 일반 변수와 조금 다릅니다. 컴파일러가 "이 변수는 확실히 캐스팅 성공한 상태야!"라고 판단할 수 있는 범위 내에서만 살아있는데, 이를 Flow Scoping이라고 합니다.
① 논리 연산자와의 궁합 (&& vs ||)
- && (AND): 왼쪽 조건이 참이어야 오른쪽을 검사하므로, 오른쪽 식에서 패턴 변수를 사용할 수 있습니다.
- || (OR): 왼쪽이 거짓이어도 오른쪽을 검사해야 하는데, 이때 변수가 캐스팅 안 되었을 수 있으므로 **사용 불가능(컴파일 에러)**합니다.
// 가능
if (obj instanceof String str && str.length() > 5) { ... }
// 에러 발생!
if (obj instanceof String str || str.length() > 5) { ... }
② if문 밖에서도 쓸 수 있다? (부정문 활용)
실무에서 가장 유용한 패턴입니다. 조건문에서 **부정(!)**을 사용하고 예외를 던지거나 리턴하면, 그 아래 코드에서는 변수를 자유롭게 쓸 수 있습니다.
public void process(Object obj) {
// String이 아니면 즉시 종료(Early Return)
if (!(obj instanceof String str)) {
return;
}
// 여기서부터는 str이 무조건 String임을 보장하므로 사용 가능!
System.out.println(str.toLowerCase());
}
4. 주의사항: 쉐도잉(Shadowing) 버그 조심!
패턴 변수를 사용할 때 가장 주의해야 할 점은 변수 이름 충돌입니다.
public class MyService {
private String str = "Global Field"; // 클래스 필드
public void test(Object obj) {
if (obj instanceof String str) { // 패턴 변수가 필드 str을 가려버림(Shadowing)
System.out.println(str); // 패턴 변수 출력
} else {
System.out.println(str); // 필드 str 출력 --> (긍정) else에는 패턴 변수 아님 클래스 필드임
}
}
}
스코프가 끝나는 지점(위 예시의 else)에서는 다시 클래스 필드를 바라보게 됩니다. 이름이 같으면 개발자가 실수로 잘못된 값을 참조할 수 있으니, 변수명을 명확하게 짓거나 충돌에 유의해야 합니다.
마치며
Java 16의 instanceof 패턴 매칭은 단순한 문법 설탕(Syntactic Sugar)을 넘어, Flow Scoping이라는 똑똑한 규칙을 통해 코드의 안정성과 가독성을 모두 잡아줍니다.
jdk21 이후에는 switch , Record 까지 확장이 되었습니다. 그래서 좋은 내용 공유차 글을 썼습니다.
혹시 잘못됐거나 질문이 있다면 댓글로 남겨주시면 감사하겠습니다 !
* 유튜브 쉬운코드 강의 참고하였습니다.
'자바 > 자바' 카테고리의 다른 글
| [Java] 제네릭 와일드카드 완벽 정리 (feat. 공변과 반공변) (1) | 2026.01.22 |
|---|---|
| [Java] 제네릭은 왜 불변(Invariant)일까? (feat. 공변과 서브타입) (1) | 2026.01.21 |
| (자바) Apache Kafka 핵심 개념 (RabbitMQ <->Redis (Pub/Sub) <->Apache Kafka 차이 ) (0) | 2025.12.15 |
| [Java] I/O 스트림과 안전한 자원 관리: Try-with-Resources 완벽 분석 (Try-Catch-Finally 비교) (0) | 2025.12.04 |
| (JAVA) 함수형 인터페이스 완벽 정리: 람다부터 스트림까지의 연결고리 (0) | 2025.12.03 |