2023년 9월 공개된 Java 21은 LTS(Long-Term Support) 버전으로, 앞으로 수년간 안정적으로 사용될 자바의 기준점이 됩니다. Java 21은 언어 차원의 진보와 성능 최적화, 그리고 개발 생산성 향상을 목표로 다양한 기능이 추가되었습니다. 특히 가상 스레드(Virtual Threads)를 포함한 Project Loom, 패턴 매칭과 스위치 문 개선, 레코드 패턴과 표준 라이브러리(API) 업데이트가 주목받고 있습니다. 이번 글에서는 Java 21의 핵심 기능들을 언어, API, 가상 스레드라는 세 가지 관점에서 살펴보고, 개발자에게 어떤 변화와 이점을 제공하는지 정리해 보겠습니다.
언어 기능 강화: 패턴 매칭과 스위치 문 진화
Java 21에서는 언어 차원의 기능 개선이 크게 눈에 띕니다. 대표적인 것이 패턴 매칭(Pattern Matching)과 스위치(Switch) 문법 개선, 그리고 레코드 패턴(Record Patterns)의 도입입니다. 기존 자바에서는 instanceof
검사와 캐스팅을 별도 단계로 나눠 처리해야 했지만, 이제는 스위치 문에서 타입 분기와 바인딩을 한 번에 처리할 수 있어 코드가 더 간결하고 안전해졌습니다. 또한 레코드 타입은 구조 분해(Destructuring) 형태로 필드를 꺼내어 사용할 수 있으므로, 데이터 중심 구조를 다루는 코드의 가독성이 크게 향상됩니다. 스위치 문은 더 엄격한 검사로 모든 경우의 수를 충족하지 않을 때 경고를 통해 누락된 분기를 알려주고, sealed 클래스와 결합하면 폐쇄적 계층 구조를 안전하게 분기 처리할 수 있도록 돕습니다.
Pattern Matching for switch를 활용하면, 값에 따라 타입별로 자연스럽게 처리할 수 있습니다. 예를 들어 다음 예시는 객체 타입에 따라 다른 형식으로 문자열을 생성합니다. null
케이스를 별도 분기로 다룰 수 있는 점도 주목할 만합니다.
static String format(Object obj) {
return switch (obj) {
case Integer i -> "정수: " + i;
case String s -> "문자열: " + s;
case null -> "널 값";
default -> obj.toString();
};
}
레코드 패턴(Record Patterns)을 활용하면 레코드 타입의 필드를 즉시 분해해 변수에 바인딩할 수 있습니다. 복잡한 중첩 구조도 단계적으로 분해가 가능해, 데이터 파이프라인이나 도메인 모델을 다루는 로직이 짧고 명료해집니다.
record Point(int x, int y) {}
static void printPoint(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println("좌표: " + x + ", " + y);
}
}
이러한 언어 기능 개선은 단지 문법 설탕(syntax sugar)에 머무르지 않습니다. 조건 분기에서의 타입 안전성 강화, 보일러플레이트 제거, 코드 가독성 및 유지보수성 향상으로 이어져, 팀 단위 개발에서 실질적인 생산성 이득을 제공합니다. 특히 비즈니스 규칙을 타입 기반으로 명확히 표현할 수 있게 되면서, 테스트 작성도 단순하고 직관적으로 바뀝니다.
API와 표준 라이브러리 확장
Java 21은 언어 차원뿐 아니라 표준 라이브러리 측면에서도 의미 있는 변화가 많습니다. 외부 라이브러리에 의존하던 영역을 점차 표준화된 API로 흡수함으로써, 개발 편의성과 성능, 안전성을 동시에 강화합니다. 대표적으로 문자열 보간을 지원하는 String 템플릿(Preview), 컬렉션의 순차적 접근을 표준화한 Sequenced Collections, JNI 대체를 목표로 성숙해진 Foreign Function & Memory(FFM) API가 눈에 띕니다.
String 템플릿 (Preview)은 기존 String.format()
보다 직관적인 문법으로 변수 값을 문자열에 삽입할 수 있게 합니다. 복잡한 포맷팅이 필요한 경우에도 가독성이 높고 오류 가능성이 적습니다.
String name = "홍길동";
int age = 30;
String msg = STR."이름: \{name}, 나이: \{age}";
System.out.println(msg);
Sequenced Collections는 리스트/셋/맵 계열에 순차성 개념을 명확히 부여해, first()
, last()
, reversed()
같은 연산을 통일된 방식으로 제공합니다. 데이터의 앞뒤를 명확히 다뤄야 하는 캐시, 덱(Deque) 스타일 처리, UI 목록 등에서 직관적이고 오류가 적은 코드를 작성할 수 있습니다.
Foreign Function & Memory API (FFM)는 JNI의 복잡도와 안전성 문제를 대체하기 위한 근본적 접근입니다. 네이티브 라이브러리를 타입 안전성 있게 호출하고, 네이티브 메모리를 자바에서 제어할 수 있도록 표준화합니다. 시스템 자원 접근, 고성능 네이티브 라이브러리 연계, 데이터 처리 파이프라인 등에서 성능과 안정성을 동시에 추구할 수 있습니다.
이 외에도 Optional
, Stream
, 정규식(Pattern
) 등의 성능 및 기능 개선이 다수 포함되어 있으며, 병렬 처리 및 대량 데이터 처리 시 체감 성능을 높이는 최적화가 반영되었습니다. 결과적으로, Java 21은 “표준 라이브러리만으로도 충분히 현대적인 개발 경험”을 제공하려는 방향성을 분명히 보여줍니다.
가상 스레드: 동시성 프로그래밍의 혁신
Java 21의 가장 큰 화두는 단연 가상 스레드(Virtual Threads)입니다. 이는 Project Loom의 핵심 산출물로, OS 스레드 1:1 매핑이라는 전통적인 모델의 무거움을 극적으로 완화합니다. 서버 애플리케이션에서 수만~수십만 동시 연결을 처리해야 할 때, 스레드 생성/전환 오버헤드는 병목이 되곤 했습니다. 가상 스레드는 JVM이 경량 스케줄링을 수행하여, 기존의 블로킹 I/O 모델을 유지하면서도 동시성 규모를 획기적으로 확대합니다.
사용성 또한 매우 뛰어납니다. 기존 Thread API와 호환되므로 학습 곡선이 낮습니다. 아래 예시처럼 Thread.startVirtualThread
를 호출하는 수준으로 시작할 수 있습니다.
Thread.startVirtualThread(() -> {
System.out.println("Hello from Virtual Thread!");
});
장점은 분명합니다. 첫째, 가상 스레드는 수십만 단위의 동시 작업을 자연스럽게 처리할 수 있어, 웹 서버/채팅 서버/DB 연결 풀과 같은 I/O 중심 애플리케이션에서 특히 큰 이점을 제공합니다. 둘째, 기존의 비동기 라이브러리(예: 콜백/리액티브)의 복잡도를 피하면서도 블로킹 코드 스타일로 단순하고 읽기 쉬운 코드를 유지할 수 있습니다. 셋째, 기존 라이브러리와의 호환성이 좋아 마이그레이션 비용이 낮습니다. 결과적으로, 코드의 단순함과 고성능 동시성이라는 두 가지 목표를 동시에 달성할 수 있게 됩니다.
물론 모든 경우에 만능은 아닙니다. CPU 바운드 작업에서는 스레드 수가 많아도 처리량이 늘지 않으며, 작업 큐/락/동기화 전략은 여전히 중요합니다. 그러나 대다수의 서버 사이드 자바 애플리케이션이 I/O 바운드라는 점을 고려할 때, 가상 스레드는 동시성 모델을 바꾸는 사실상의 표준이 될 잠재력을 지닌 기능입니다.
결론: Java 21은 미래 자바의 표준
Java 21은 단순한 기능 추가를 넘어, 자바가 미래에도 경쟁력 있는 언어로 남을 수 있음을 보여주는 버전입니다. 요약하면 다음과 같습니다.
- 언어 기능 개선: 패턴 매칭, 스위치, 레코드 패턴 → 가독성과 안정성 강화
- API 확장: String 템플릿, Sequenced Collections, FFM API → 생산성·성능·안전성 향상
- 가상 스레드: 대규모 동시성 처리의 혁신 → 단순한 코드로 고성능 실현
LTS 버전이라는 점에서 Java 21은 기업과 프로젝트의 새 기준이 될 가능성이 큽니다. 지금 바로 새로운 기능을 학습하고, 파일럿 프로젝트나 신규 모듈부터 적용해 보세요. 언어·라이브러리·동시성의 세 축에서 얻는 생산성과 성능의 이점을 통해, 팀의 개발 경험을 한 단계 끌어올릴 수 있을 것입니다.