Enhance the Java programming language with record patterns to deconstruct record values. Record patterns and type patterns can be nested to enable a powerful, declarative, and composable form of data navigation and processing.
레코드 값을 분해하기 위한 레코드 패턴으로 자바 프로그래밍 언어를 강화한다. 레코드 패턴과 타입 패턴은 중첩될 수 있어서, 강력하고 선언적이며 조합 가능한 형태의 데이터 탐색 및 처리를 가능하게 한다.
if (obj instanceof Point) {
Point p = (Point) obj; // 형변환 직접
int x = p.x(); // 값 하나씩 꺼내기
int y = p.y();
System.out.println(x + ", " + y);
}
if (obj instanceof Point(int x, int y)) { // 분해까지 한 줄에
System.out.println(x + ", " + y); // 바로 x, y 사용
}
Enhance the Java programming language with pattern matching for switch expressions and statements. Extending pattern matching to switch allows an expression to be tested against a number of patterns, each with a specific action, so that complex data-oriented queries can be expressed concisely and safely.
switch 식과 문을 위한 패턴 매칭으로 자바 프로그래밍 언어를 강화한다. 패턴 매칭을 switch로 확장하면, 하나의 식을 여러 패턴에 대해 각각 특정 동작과 함께 테스트할 수 있게 되어, 복잡한 데이터 중심 쿼리를 간결하고 안전하게 표현할 수 있다.
String describe(Object obj) {
if (obj instanceof Point p) {
return "점: " + p.x() + "," + p.y();
} else if (obj instanceof Line l) {
return "선";
} else {
return "몰라";
}
}
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) -> "점: " + x + "," + y;
case Line(Point s, Point e) -> "선";
default -> "몰라";
};
}
Enhance the Java programming language with string templates. String templates complement Java's existing string literals and text blocks by coupling literal text with embedded expressions and template processors to produce specialized results.
string templates로 자바 프로그래밍 언어를 강화한다. string templates는 리터럴 텍스트를 내장된 표현식 및 템플릿 프로세서와 결합함으로써, 자바의 기존 string literal과 text block을 보완하여 특화된 결과를 만들어낸다. ※ 이 기능은 이후 Java 23에서 설계 문제로 제거됨. "이런 시도가 있었다" 정도로 참고.
String name = "홍길동";
int age = 30;
// + 로 붙이기
String msg1 = name + "님은 " + age + "살입니다";
// 또는 String.format (자리표시자 순서 실수 위험)
String msg2 = String.format("%s님은 %d살입니다", name, age);
String name = "홍길동";
int age = 30;
// 문자열 안에 값을 직접 끼워넣음
String msg = STR."\{name}님은 \{age}살입니다";
Enhance the Java language with unnamed patterns, which match a record component without stating the component's name or type, and unnamed variables, which can be initialized but not used. Both are denoted by an underscore character, _.
record 구성 요소를 그 요소의 이름이나 타입을 명시하지 않고 매칭하는 이름 없는 패턴, 그리고 초기화될 수 있지만 사용되지 않는 이름 없는 변수로 자바 언어를 강화한다. 둘 다 밑줄 문자 _로 표시된다.
// 안 쓸 값인데도 억지로 이름을 붙여야 함
try {
int n = Integer.parseInt(input);
} catch (NumberFormatException e) { // e를 안 쓰는데 이름 필요
System.out.println("숫자 아님");
}
if (obj instanceof Point(int x, int y)) { // y 안 쓰는데 이름 필요
System.out.println("x좌표: " + x);
}
// 안 쓸 값은 _ 로 표시
try {
int n = Integer.parseInt(input);
} catch (NumberFormatException _) { // _
System.out.println("숫자 아님");
}
if (obj instanceof Point(int x, _)) { // y 자리를 _
System.out.println("x좌표: " + x);
}
Evolve the Java language so that students can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of Java, students can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow.
학생들이 큰 프로그램을 위해 설계된 언어 기능들을 이해할 필요 없이 첫 프로그램을 작성할 수 있도록 자바 언어를 발전시킨다. 자바의 별개 방언을 쓰는 것과는 거리가 멀게(결코 방언이 아니라), 학생들은 단일 클래스 프로그램을 위한 간결한 선언을 작성하고, 이후 실력이 자람에 따라 매끄럽게 더 고급 기능을 쓰도록 프로그램을 확장할 수 있다.
// Hello World 한 줄에 public/static/class를 다 알아야 함
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
// 클래스도 public static도 없이 바로
void main() {
System.out.println("Hello World");
}
Introduce virtual threads to the Java Platform. Virtual threads are lightweight threads that dramatically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications.
virtual threads를 자바 플랫폼에 도입한다. virtual threads는 고처리량 동시성 애플리케이션을 작성하고, 유지보수하고, 관찰하는 노력을 획기적으로 줄여주는 가벼운 스레드다. 줄어드는 건 "성능"이 아니라 "노력(effort)". 기다림이 많은 서버 작업에서 특히 효과적. Java 21 정식 기능.
// 무거운 스레드 → 개수 제한된 풀로 돌려막기
ExecutorService executor = Executors.newFixedThreadPool(200);
for (int i = 0; i < 10000; i++) {
executor.submit(() -> callDatabase()); // 200개뿐이라 대기 발생
}
// 요청마다 가벼운 가상 스레드 → 제한 없이
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10000; i++) {
executor.submit(() -> callDatabase()); // 1만 개 동시에 OK
}
Introduce new interfaces to represent collections with a defined encounter order. Each such collection has a well-defined first element, second element, and so forth, up to the last element. It also provides uniform APIs for accessing its first and last elements, and for processing its elements in reverse order.
정해진 등장 순서(encounter order)를 가진 컬렉션을 나타내기 위한 새로운 인터페이스를 도입한다. 그러한 각 컬렉션은 명확한 첫 번째 요소, 두 번째 요소, 그런 식으로 마지막 요소까지 가진다. 또한 첫 번째와 마지막 요소에 접근하기 위한, 그리고 요소들을 역순으로 처리하기 위한 통일된 API를 제공한다.
// 컬렉션마다 첫/마지막 접근 방법이 제각각
List list = new ArrayList<>(List.of("a","b","c"));
String first = list.get(0);
String last = list.get(list.size() - 1); // size-1 계산
// LinkedHashSet의 마지막은 방법이 없어 전체 순회
String setLast = null;
for (String s : set) { setLast = s; }
// 어떤 컬렉션이든 동일한 메서드로 통일
String first = list.getFirst();
String last = list.getLast(); // 계산 불필요
String setLast = set.getLast(); // 한 줄로 끝
for (String s : list.reversed()) { ... } // 역순도 통일
Introduce an API for key encapsulation mechanisms (KEMs), an encryption technique for securing symmetric keys using public key cryptography.
key encapsulation mechanisms(KEMs)를 위한 API를 도입한다. (KEM은) 공개 키 암호화를 사용하여 대칭 키를 보호하기 위한 암호화 기법이다. 암호화를 직접 구현하는 소수만 쓰는 API. 양자 컴퓨터 대비 차세대 암호의 기반. 개념만 알면 충분.
// 위험한 패딩 문자열을 직접 골라야 함 (실수 시 취약)
Cipher cipher = Cipher.getInstance(
"RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.WRAP_MODE, receiverPublicKey);
byte[] wrappedKey = cipher.wrap(symmetricKey);
// 알고리즘 바꾸면 코드도 전부 달라짐
// 알고리즘 무관하게 통일된 방식, 패딩 걱정 없음
KEM kem = KEM.getInstance("DHKEM-X25519-HKDF-SHA256");
KEM.Encapsulator sender = kem.newEncapsulator(receiverPublicKey);
KEM.Encapsulated result = sender.encapsulate();
SecretKey key = result.key(); // 바로 쓸 대칭 키
byte[] capsule = result.encapsulation(); // 보낼 캡슐
Introduce an API by which Java programs can interoperate with code and data outside of the Java runtime. By efficiently invoking foreign functions (i.e., code outside the JVM), and by safely accessing foreign memory (i.e., memory not managed by the JVM), the API enables Java programs to call native libraries and process native data without the brittleness and danger of JNI.
자바 프로그램이 자바 런타임 바깥의 코드 및 데이터와 상호작용할 수 있게 해주는 API를 도입한다. 외부 함수(즉, JVM 밖의 코드)를 효율적으로 호출하고, 외부 메모리(즉, JVM이 관리하지 않는 메모리)에 안전하게 접근함으로써, 이 API는 자바 프로그램이 JNI의 취약함과 위험 없이 네이티브 라이브러리를 호출하고 네이티브 데이터를 처리할 수 있게 한다. JNI(1997년부터 있던 방식)는 복잡하고 실수하면 JVM이 크래시 나던 위험이 있었는데, 그걸 안전·간편하게 대체하는 API. Java 22에서 정식화.
// 1) 자바: native 메서드 선언
public native long strlen(String str);
static { System.loadLibrary("mynative"); }
// 2) C 코드를 JNI 규칙대로 따로 작성해야 함
JNIEXPORT jlong JNICALL Java_MyNative_strlen
(JNIEnv *env, jobject o, jstring str) {
const char *c = (*env)->GetStringUTFChars(env, str, NULL);
jlong len = strlen(c);
(*env)->ReleaseStringUTFChars(env, str, c); // 수동 해제
return len;
}
// 3) OS별로 컴파일 → .dll/.so 빌드 필요
// 순수 자바만으로 C 함수 호출 (C 코드 0줄)
Linker linker = Linker.nativeLinker();
MethodHandle strlen = linker.downcallHandle(
linker.defaultLookup().find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
try (Arena arena = Arena.ofConfined()) {
MemorySegment s = arena.allocateUtf8String("Hello");
long len = (long) strlen.invoke(s); // C의 strlen 호출
} // 블록 끝나면 메모리 자동 해제
Simplify concurrent programming by introducing an API for structured concurrency. Structured concurrency treats groups of related tasks running in different threads as a single unit of work, thereby streamlining error handling and cancellation, improving reliability, and enhancing observability.
구조화된 동시성(structured concurrency)을 위한 API를 도입함으로써 동시성 프로그래밍을 단순화한다. 구조화된 동시성은 서로 다른 스레드에서 실행되는 관련 작업들의 그룹을 하나의 작업 단위로 취급하며, 그럼으로써 오류 처리와 취소를 간소화하고, 신뢰성을 향상시키고, 관측성을 높인다. 동시 작업들을 try-with-resources처럼 하나의 블록으로 묶는 방식. 하나 실패하면 다 같이 정리됨. Java 21은 Preview(이후 API 변경됨).
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
Future profile = executor.submit(() -> fetchProfile());
Future settings = executor.submit(() -> fetchSettings());
// 하나 실패해도 다른 건 계속 돎, 취소 수동 처리
return profile.get() + " / " + settings.get();
} finally {
executor.shutdown(); // 수동 정리
}
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var profile = scope.fork(() -> fetchProfile());
var settings = scope.fork(() -> fetchSettings());
scope.join(); // 둘 다 끝날 때까지 대기
scope.throwIfFailed(); // 하나라도 실패하면 예외 + 나머지 자동 취소
return profile.get() + " / " + settings.get();
} // scope 벗어나면 자동 정리
Introduce scoped values, values that may be safely and efficiently shared to methods without using method parameters. They are preferred to thread-local variables, especially when using large numbers of virtual threads.
scoped values를 도입한다. (scoped values는) 메서드 파라미터를 사용하지 않고도 안전하고 효율적으로 메서드에 공유될 수 있는 값이다. 이것들은 특히 많은 수의 가상 스레드를 사용할 때, thread-local 변수보다 선호된다. 정해진 범위(scope) 안에서만 살아있고 벗어나면 자동으로 사라지는 값. 가상 스레드 환경에서 ThreadLocal을 대체. 단, 명시성이 떨어지므로 프레임워크성 값에만 신중히 쓸 것.
static final ThreadLocal USER = new ThreadLocal<>();
void handleRequest(User user) {
USER.set(user);
try {
processOrder(); // 파라미터 없이 호출
} finally {
USER.remove(); // 반드시 지워야 함 (누수 위험)
}
}
void saveToDb() {
User user = USER.get(); // 아무나 set으로 덮어쓸 수도 있음
}
static final ScopedValue USER = ScopedValue.newInstance();
void handleRequest(User user) {
ScopedValue.where(USER, user).run(() -> {
processOrder(); // 파라미터 없이 호출
});
// 블록 끝나면 자동 소멸 (remove 불필요), 중간 변경 불가(불변)
}
void saveToDb() {
User user = USER.get();
}
JDK 21 Release Notes — oracle.com/java/technologies/javase/21-relnote-issues.html
'릴리스노트' 카테고리의 다른 글
| Java 22 릴리스 노트 (1) | 2026.07.20 |
|---|---|
| Spring Boot 4.0 릴리스 노트 독해 겸 정리 (0) | 2026.07.10 |