Java

Java 24

창욱씨 2026. 5. 16. 17:16
반응형

✅ 정식 출시 (Finalized)


JEP 484 · Class-File API

.class 바이트코드 파일을 읽고, 쓰고, 변환하는 표준 API입니다.

기존에는 바이트코드를 다루려면 ASM, Javassist 같은 서드파티 라이브러리에 의존해야 했습니다. 이제 JDK 자체에서 공식 지원합니다.

// 클래스 파일 읽기 예시
ClassFile cf = ClassFile.of();
ClassModel classModel = cf.parse(Path.of("MyClass.class"));

classModel.methods().forEach(method -> {
    System.out.println("Method: " + method.methodName().stringValue());
});

활용 사례:

  • 프레임워크 개발 (Spring, Hibernate 등 내부 바이트코드 조작)
  • 커버리지 툴, 프로파일러
  • 코드 변환 도구

JEP 485 · Stream Gatherers

Stream중간 연산을 직접 커스터마이징할 수 있는 gather() API입니다.

기존 스트림은 filter, map, limit 등 정해진 연산만 가능했지만, 이제 직접 만든 중간 연산을 삽입할 수 있습니다.

// 연속된 중복 제거 (커스텀 중간 연산)
Stream.of(1, 1, 2, 2, 3, 1, 1)
    .gather(Gatherers.fold(() -> new ArrayList<>(), (list, e) -> {
        if (list.isEmpty() || !list.get(list.size()-1).equals(e))
            list.add(e);
        return list;
    }))
    .forEach(System.out::println);
// 출력: 1, 2, 3, 1

// JDK 기본 제공 Gatherers
Stream.of(1,2,3,4,5)
    .gather(Gatherers.windowFixed(2))  // [1,2], [3,4], [5]
    .forEach(System.out::println);

기본 제공 Gatherers:
| 메서드 | 설명 |
|--------|------|
| windowFixed(n) | n개씩 묶어서 List로 |
| windowSliding(n) | 슬라이딩 윈도우 |
| fold(init, fn) | 누적 연산 |
| scan(init, fn) | 중간 누적값 포함 |


JEP 487 · Scoped Values

스레드 간 불변 데이터를 안전하게 공유하는 메커니즘입니다.
기존 ThreadLocal의 단점(변경 가능, 메모리 누수 위험)을 해결한 대안입니다.

// ScopedValue 선언
static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();

void handleRequest(User user) {
    // 특정 범위(scope) 안에서만 값이 유효
    ScopedValue.where(CURRENT_USER, user).run(() -> {
        processRequest();
    });
}

void processRequest() {
    User user = CURRENT_USER.get(); // 안전하게 접근
    System.out.println("현재 사용자: " + user.name());
}

ThreadLocal과 비교:
| 항목 | ThreadLocal | ScopedValue |
|------|--------------|---------------|
| 변경 가능 여부 | ✅ 가능 | ❌ 불변 |
| 메모리 누수 위험 | ⚠️ 있음 | ✅ 없음 |
| 가상 스레드 지원 | ⚠️ 비효율적 | ✅ 최적화 |
| 유효 범위 | 스레드 전체 | 명시적 scope |


JEP 490 · ZGC: Generational Mode by Default

Z Garbage Collector(ZGC)의 세대별(Generational) 모드가 기본값으로 설정되었습니다.

"대부분의 객체는 생성 직후 곧 죽는다" — 세대별 가설(Generational Hypothesis)

# 이전 Java 23까지
-XX:+UseZGC -XX:+ZGenerational  ← 명시적으로 켜야 했음

# Java 24부터
-XX:+UseZGC  ← 자동으로 세대별 모드 사용

# 구 모드로 되돌리려면
-XX:+UseZGC -XX:-ZGenerational

효과:

  • 단기 객체는 Young Generation에서 빠르게 수거
  • GC 오버헤드 감소
  • 처리량(Throughput) 및 지연시간(Latency) 동시 개선

JEP 491 · Synchronized Virtual Threads

가상 스레드가 synchronized 블록 진입 시 플랫폼 스레드에 고정(pin)되던 문제를 해결했습니다.

// 기존(Java 23 이하): synchronized 블록에서 가상 스레드가 pin됨
// → 플랫폼 스레드를 점유해 다른 가상 스레드 실행 불가

// Java 24: pin 없이 동작
synchronized (lock) {
    // I/O 작업 등 블로킹 발생해도
    // 플랫폼 스레드를 해제하고 다른 가상 스레드가 실행 가능
    Files.readAllBytes(path);
}

// 대규모 가상 스레드 활용 예
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 100_000; i++) {
        executor.submit(() -> {
            synchronized (sharedLock) {
                doBlockingWork(); // 이제 안전하게 확장 가능
            }
        });
    }
}

영향:

  • synchronizedReentrantLock으로 마이그레이션하지 않아도 됨
  • 기존 레거시 코드도 가상 스레드의 이점을 바로 누릴 수 있음

🔄 Preview / Incubator


JEP 488 · Primitive Types in Patterns (2차 Preview)

instanceofswitch에서 원시 타입(int, long, double 등)도 패턴 매칭 가능합니다.

// instanceof에서 원시 타입 패턴
Object obj = 42;
if (obj instanceof int i) {  // 언박싱 자동 처리
    System.out.println("정수: " + i);
}

// switch에서 원시 타입
switch (someDouble) {
    case 0.0 -> System.out.println("영");
    case double d when d > 0 -> System.out.println("양수: " + d);
    case double d -> System.out.println("음수: " + d);
}

// 넓은 타입 변환도 지원
long bigNum = 100L;
if (bigNum instanceof int i) {  // 범위 체크 후 변환
    System.out.println("int 범위: " + i);
}

JEP 492 · Flexible Constructor Bodies (3차 Preview)

생성자에서 super() 또는 this() 호출 전에 코드 실행을 허용합니다.

// 기존: super() 전에 아무것도 못 씀
class OldStyle extends Parent {
    OldStyle(int value) {
        super(validate(value)); // 검증 로직을 static 메서드로 강제 분리
    }
}

// Java 24: super() 전에 검증/준비 코드 가능
class NewStyle extends Parent {
    NewStyle(int value) {
        // super() 호출 전 코드 허용!
        if (value < 0) throw new IllegalArgumentException("음수 불가");
        var adjusted = value * 2;
        super(adjusted); // 이후 super() 호출
    }
}

JEP 494 · Module Import Declarations (2차 Preview)

모듈 단위로 한 번에 import 하는 기능입니다.

// 기존: 패키지마다 개별 import
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import java.io.IOException;
// ...수십 줄의 import

// Java 24: 모듈 단위 일괄 import
import module java.base;  // java.base 모듈의 모든 패키지 import

public class Main {
    public static void main(String[] args) {
        List<String> list = List.of("a", "b", "c");
        Map<String, Integer> map = Map.of("x", 1);
        Stream<String> stream = list.stream();
    }
}

학습용, 프로토타이핑, 스크립트 작성 시 특히 유용합니다.


JEP 495 · Simple Source Files & Instance Main Methods (4차 Preview)

초보자 친화적인 간결한 Java 프로그램 작성을 지원합니다.

// Java 24: 클래스 선언, static, String[] args 모두 생략 가능!
void main() {
    System.out.println("Hello, Java 24!");
}

// 인스턴스 메서드로 main 작성도 가능
class Greeter {
    void main() {
        var name = "World";
        System.out.println("Hello, " + name);
    }
}

기존 방식과 비교:

// 기존 방식 (여전히 유효)
public class OldMain {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Python, Kotlin처럼 교육 목적으로 진입 장벽을 낮추는 것이 목표입니다.


JEP 499 · Structured Concurrency (4차 Preview)

여러 비동기 작업을 하나의 논리적 단위로 관리하는 API입니다.

// 여러 작업을 구조적으로 관리
Response handle() throws InterruptedException, ExecutionException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        // 두 작업을 병렬 실행
        Subtask<User> userTask = scope.fork(() -> fetchUser(userId));
        Subtask<Order> orderTask = scope.fork(() -> fetchOrder(orderId));

        scope.join()           // 두 작업 모두 완료 대기
             .throwIfFailed(); // 하나라도 실패 시 예외

        // 두 결과 모두 성공적으로 사용 가능
        return new Response(userTask.get(), orderTask.get());
    }
    // scope 종료 시 미완료 작업 자동 취소
}
반응형

'Java' 카테고리의 다른 글

Java 23  (0) 2026.05.06
Java에서 데이터 없음을 표현하는 방법  (0) 2026.04.18
Synchronized & ReentrantLock  (0) 2025.07.15
ThreadLocal  (0) 2020.05.26
Java 예외 처리  (0) 2020.04.25