Java 25의 새로운 기능: 검증된 LTS 릴리스 가이드

이성혁·2025년 9월 17일
post-thumbnail

2025년 9월, Oracle이 Java 25를 공식 출시했습니다. Java 25는 Java 21 이후 첫 번째 LTS(Long-Term Support) 릴리스로, 최소 8년간의 장기 지원이 보장됩니다. 총 18개의 JEP(Java Enhancement Proposal)를 포함한 이번 릴리스는 성능 최적화, 개발자 생산성, 그리고 현대적인 프로그래밍 패러다임에 대한 지원을 크게 향상시켰습니다.

전체 JEP 현황 (18개)

정식 기능 (Stable) - 11개

  • JEP 506: Scoped Values
  • JEP 510: Key Derivation Function API
  • JEP 511: Module Import Declarations
  • JEP 512: Compact Source Files and Instance Main Methods
  • JEP 513: Flexible Constructor Bodies
  • JEP 514: Ahead-of-Time Command-Line Ergonomics
  • JEP 515: Ahead-of-Time Method Profiling
  • JEP 518: JFR Cooperative Sampling
  • JEP 519: Compact Object Headers
  • JEP 520: JFR Method Timing & Tracing
  • JEP 521: Generational Shenandoah

프리뷰 기능 (Preview) - 4개

  • JEP 470: PEM Encodings of Cryptographic Objects (Preview)
  • JEP 502: Stable Values (Preview)
  • JEP 505: Structured Concurrency (Fifth Preview)
  • JEP 507: Primitive Types in Patterns, instanceof, and switch (Third Preview)

인큐베이터 기능 (Incubator) - 1개

  • JEP 508: Vector API (Tenth Incubator)

실험적 기능 (Experimental) - 1개

  • JEP 509: JFR CPU-Time Profiling (Experimental)

제거된 기능 (Removal) - 1개

  • JEP 503: Remove the 32-bit x86 Port

주요 언어 기능

1. 모듈 임포트 선언 (Module Import Declarations, JEP 511) ✅ 정식

Java 25에서 가장 주목할 만한 기능 중 하나는 모듈 전체를 한 번에 임포트할 수 있는 새로운 구문입니다. 기존에는 모듈의 여러 패키지를 사용하려면 각각을 개별적으로 임포트해야 했지만, 이제는 import module 구문을 사용하여 모듈이 내보내는 모든 패키지를 간결하게 임포트할 수 있습니다.

기존 방식:

import java.util.*;
import java.time.*;
import java.nio.*;
// 여러 개의 import 문이 필요

Java 25의 새로운 방식:

import module java.base;

public class Main {
    public static void main(String[] args) {
        Date d = new Date();
        LocalDateTime now = LocalDateTime.now();
        Path path = Paths.get("/tmp");
        System.out.println("간결한 모듈 임포트: " + d);
    }
}

이 기능의 핵심 장점:

  • 모듈러 라이브러리 재사용의 간소화
  • 개발자가 자신의 코드를 모듈화하지 않아도 사용 가능
  • 클래스패스에서만 배포되는 코드에서도 사용 가능

2. 패턴에서의 원시 타입 (Primitive Types in Patterns, JEP 507) 🔄 Third Preview

세 번째 프리뷰 단계에 있는 이 기능은 패턴 매칭을 원시 타입으로 확장합니다. 이전 버전에서는 패턴 매칭이 참조 타입에만 사용 가능했지만, 이제 int, double 등의 원시 타입도 직접 매칭할 수 있습니다.

기존 방식:

static void processValue(Object obj) {
    if (obj instanceof Integer) {
        Integer i = (Integer) obj;
        System.out.println("정수 값: " + i);
    } else if (obj instanceof Double) {
        Double d = (Double) obj;
        System.out.println("실수 값: " + d);
    }
}

Java 25의 새로운 방식:

static void processValue(Object obj) {
    switch (obj) {
        case int i -> System.out.println("정수 값: " + i);
        case double d -> System.out.println("실수 값: " + d);
        case String s -> System.out.println("문자열 값: " + s);
        default -> System.out.println("알 수 없는 타입");
    }
}

// instanceof와 함께 사용
static void testInstance(Object obj) {
    if (obj instanceof int i) {
        System.out.println("정수입니다: " + i);
    }
}

3. 유연한 생성자 본문 (Flexible Constructor Bodies, JEP 513) ✅ 정식

이 기능은 생성자에서 super() 또는 this() 호출 전에 검증 로직이나 안전한 계산을 수행할 수 있도록 합니다. 기존에는 생성자의 첫 번째 문장이 반드시 다른 생성자 호출이어야 했지만, 이제는 더 유연한 구조가 가능합니다.

기존 방식의 제약:

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        // super() 호출 전에는 어떤 로직도 실행할 수 없었음
        super();
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("이름은 필수입니다");
        }
        this.name = name;
        this.age = age;
    }
}

Java 25의 새로운 방식:

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        // super() 호출 전에 검증 로직 실행 가능
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("이름은 필수입니다");
        }
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("유효하지 않은 나이입니다");
        }

        super();
        this.name = name.trim();
        this.age = age;
    }
}

4. 간결한 소스 파일과 인스턴스 메인 메서드 (Compact Source Files, JEP 512) ✅ 정식

Java 초보자들을 위한 진입 장벽을 낮추는 기능으로, 간단한 프로그램을 더욱 간결하게 작성할 수 있습니다.

기존 방식:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("안녕하세요, 세상!");
    }
}

Java 25의 새로운 방식:

void main() {
    System.out.println("안녕하세요, 세상!");
}

동시성 및 성능 개선

5. 구조적 동시성 (Structured Concurrency, JEP 505) 🔄 Fifth Preview

다섯 번째 프리뷰 단계에 있는 구조적 동시성은 여러 스레드에서 실행되는 관련 작업들을 하나의 작업 단위로 처리하여 동시 프로그래밍을 단순화합니다.

import java.util.concurrent.StructuredTaskScope;

public class DataProcessor {
    public Result processData() throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            var userTask = scope.fork(() -> fetchUserData());
            var orderTask = scope.fork(() -> fetchOrderData());
            var productTask = scope.fork(() -> fetchProductData());

            scope.join();           // 모든 작업 완료 대기
            scope.throwIfFailed();  // 실패 시 예외 발생

            return new Result(
                userTask.resultNow(),
                orderTask.resultNow(),
                productTask.resultNow()
            );
        }
    }
}

6. 스코프 값 (Scoped Values, JEP 506) ✅ 정식

스레드 로컬 변수보다 효율적인 대안으로 정식 기능화되었습니다. 메서드가 스레드 내의 호출자와 자식 스레드와 불변 데이터를 공유할 수 있게 해줍니다.

public class RequestProcessor {
    public static final ScopedValue<String> REQUEST_ID =
        ScopedValue.newInstance();

    public void processRequest(String requestId) {
        ScopedValue.where(REQUEST_ID, requestId)
            .run(() -> {
                // 이 범위 내에서 REQUEST_ID를 사용할 수 있음
                handleRequest();
            });
    }

    private void handleRequest() {
        String id = REQUEST_ID.get(); // 현재 요청 ID 획득
        System.out.println("처리 중인 요청: " + id);
        // 하위 메서드에서도 REQUEST_ID 접근 가능
        callSubMethod();
    }
}

7. 안정 값 (Stable Values, JEP 502) 🔄 Preview

JVM이 상수로 취급하는 객체를 위한 API를 도입하여, final 변수와 동일한 성능 혜택을 제공합니다.

public class ConfigurationManager {
    private static final StableValue<DatabaseConfig> DB_CONFIG =
        StableValue.of(loadDatabaseConfig());

    public DatabaseConfig getDatabaseConfig() {
        return DB_CONFIG.get(); // JVM에서 상수로 최적화
    }
}

보안 및 암호화

8. 키 유도 함수 API (Key Derivation Function API, JEP 510) ✅ 정식

암호화 키를 사용자 패스워드로부터 유도하는 표준화된 API를 제공합니다. PBKDF2, Argon2, scrypt 등의 알고리즘을 지원합니다.

import javax.crypto.KDF;
import javax.crypto.spec.PBKDF2ParameterSpec;

public class PasswordProcessor {
    public byte[] deriveKey(char[] password, byte[] salt) {
        PBKDF2ParameterSpec spec = new PBKDF2ParameterSpec(
            password, salt, 100_000, 256, "HmacSHA256");

        KDF kdf = KDF.getInstance("PBKDF2");
        return kdf.deriveKey(spec);
    }
}

9. 암호화 객체의 PEM 인코딩 (PEM Encodings, JEP 470) 🔄 Preview

PEM 형식의 암호화 키, 인증서, 인증서 해지 목록을 인코딩/디코딩하는 API를 제공합니다.

import java.security.cert.X509Certificate;
import java.security.PEMEncoder;
import java.security.PEMDecoder;

public class CertificateHandler {
    public String encodeCertificate(X509Certificate cert) {
        PEMEncoder encoder = PEMEncoder.getInstance();
        return encoder.encode(cert);
    }

    public X509Certificate decodeCertificate(String pemString) {
        PEMDecoder decoder = PEMDecoder.getInstance();
        return (X509Certificate) decoder.decode(pemString);
    }
}

JVM 및 런타임 개선사항

10. JFR CPU 시간 프로파일링 (JEP 509) 🧪 Experimental

Java Flight Recorder에 CPU 시간 기반 프로파일링 지원이 추가되어, 특정 메서드나 스레드에서 소비되는 CPU 시간을 정확하게 측정할 수 있습니다.

11. 컴팩트 객체 헤더 (Compact Object Headers, JEP 519) ✅ 정식

실험적 기능에서 정식 제품 옵션으로 승격되어, 자바 힙 메모리 사용량을 줄이고 성능 향상을 제공합니다.

# 컴팩트 객체 헤더 활성화
java -XX:+UseCompactObjectHeaders MyApplication

12. 벡터 API (Vector API, JEP 508) 🔬 Tenth Incubator

열 번째 인큐베이터 단계에 있는 벡터 API는 지원되는 CPU에서 최적화된 벡터 명령어로 컴파일되는 벡터 계산을 표현할 수 있게 해줍니다.

import jdk.incubator.vector.*;

public class VectorExample {
    static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

    public void vectorAdd(float[] a, float[] b, float[] c) {
        int length = a.length;
        int loopBound = SPECIES.loopBound(length);

        for (int i = 0; i < loopBound; i += SPECIES.length()) {
            var va = FloatVector.fromArray(SPECIES, a, i);
            var vb = FloatVector.fromArray(SPECIES, b, i);
            var vc = va.add(vb);
            vc.intoArray(c, i);
        }
    }
}

13. Generational Shenandoah (JEP 521) ✅ 정식

Red Hat에서 개발한 Shenandoah 가비지 컬렉터에 generational 모드가 정식으로 추가되었습니다. 젊은 세대 객체들을 더 효율적으로 수집하여 일시 정지 시간을 줄이고 처리량을 향상시킵니다.

# Generational Shenandoah 활성화
java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational MyApplication

주요 개선사항:

  • JDK 24에서 실험적 기능이었으나 Java 25에서 정식 기능으로 승격
  • -XX:+UnlockExperimentalVMOptions 플래그가 더 이상 필요하지 않음
  • 젊은 세대 객체의 효율적인 수집으로 성능 향상

14. JFR 개선사항

JFR Method Timing & Tracing (JEP 520) ✅ 정식:

  • 바이트코드 계측을 통한 메서드 타이밍 및 추적 기능
  • 애플리케이션 성능 병목 지점 식별 및 최적화 지원

JFR Cooperative Sampling (JEP 518) ✅ 정식:

  • 협력적 샘플링을 통한 더 정확한 프로파일링
  • 오버헤드 감소와 정확도 향상

15. Ahead-of-Time (AOT) 개선

AOT Command-Line Ergonomics (JEP 514) ✅ 정식:

  • Project Leyden의 일환으로 AOT 컴파일을 위한 명령줄 인터페이스 개선

AOT Method Profiling (JEP 515) ✅ 정식:

  • 메서드 프로파일링을 통한 AOT 최적화 향상

16. 32비트 x86 포트 제거 (JEP 503) ❌ 제거

레거시 32비트 x86 아키텍처(Linux)에 대한 지원을 완전히 제거하여 유지보수 오버헤드를 줄였습니다. JDK 24에서 32비트 Windows 포트가 제거된 것에 이어, 모든 32비트 포트가 완전히 제거되었습니다.

영향:

  • 32비트 Linux 시스템에서 Java 25 실행 불가
  • 해당 사용자들은 64비트 JVM으로 마이그레이션 필요
  • Loom, FFM API, Vector API 등 최신 기능 지원 비용 절감

실무에서의 활용

Java 25의 새로운 기능들은 실무에서 다음과 같은 이점을 제공합니다:

1. 개발 생산성 향상

  • 모듈 임포트: 대규모 라이브러리 사용 시 import 문 개수 대폭 감소
  • 간결한 소스 파일: 교육용 코드와 스크립트 작성의 간소화
  • 유연한 생성자: 더 나은 validation 로직 배치

2. 성능 최적화

  • Generational Shenandoah: 젊은 세대 객체 수집 최적화로 GC 성능 향상
  • 컴팩트 객체 헤더: 메모리 사용량 감소와 캐시 효율성 증대
  • 벡터 API: SIMD 명령어 활용한 수치 연산 성능 향상
  • 안정 값 API: JVM 최적화를 통한 상수 접근 성능 향상

3. 보안 강화

  • 키 유도 함수 API: 표준화된 패스워드 기반 키 생성으로 보안성 향상
  • PEM 인코딩 API: 인증서 및 키 관리의 표준화

4. 동시성 프로그래밍 개선

  • 구조적 동시성: 멀티스레드 프로그래밍의 안전성과 가독성 증대
  • 스코프 값: 스레드 로컬 변수 대체로 성능과 메모리 효율성 향상

5. 모니터링 및 프로파일링 향상

  • JFR 개선사항: 더 정확하고 효율적인 애플리케이션 성능 분석
  • AOT 최적화: 시작 시간 단축과 메모리 사용량 최적화

마이그레이션 가이드

Java 25로의 마이그레이션을 위해서는:

1. 호환성 확인

  • 플랫폼 요구사항: 64비트 시스템 필수 (32비트 지원 완전 제거)
  • 라이브러리 호환성: 기존 라이브러리와 프레임워크의 Java 25 호환성 확인
  • 빌드 도구: Maven, Gradle 등 빌드 도구의 Java 25 지원 확인

2. 단계적 적용

  • Preview 기능: JEP 470, 502, 505, 507은 프로덕션 환경에서 신중히 사용
  • 새로운 기능: 모듈 임포트, 유연한 생성자 등 정식 기능부터 도입
  • GC 설정: Generational Shenandoah 등 새로운 GC 옵션 테스트

3. 테스트 강화

  • 패턴 매칭: 원시 타입 패턴 매칭 사용 시 충분한 단위 테스트
  • 동시성: 구조적 동시성과 스코프 값 사용 시 멀티스레드 테스트
  • 성능 테스트: 새로운 JVM 옵션 적용 후 성능 회귀 테스트

4. 성능 모니터링

  • JFR 활용: 새로운 JFR 기능을 활용한 상세한 성능 모니터링
  • 메모리 사용량: 컴팩트 객체 헤더 적용 시 힙 메모리 사용량 변화 관찰
  • GC 성능: Generational Shenandoah 적용 시 GC 지표 모니터링

결론

Java 25는 LTS 릴리스로서 안정성과 혁신성을 모두 갖춘 중요한 업데이트입니다. 18개의 JEP를 통해 언어 기능 개선, 성능 최적화, 보안 강화, 그리고 개발자 경험 향상을 제공합니다.

특히 주목할 만한 점들:

언어 진화

  • 모듈 시스템의 실용성 증대 (JEP 511)
  • 패턴 매칭의 원시 타입 확장 (JEP 507)
  • 생성자 유연성 향상 (JEP 513)

성능 혁신

  • Generational Shenandoah의 정식 도입 (JEP 521)
  • 메모리 효율성 개선 (JEP 519)
  • 벡터 연산 최적화 (JEP 508)

보안 표준화

  • 암호화 키 관리 API 정식화 (JEP 510)
  • PEM 인코딩 표준 지원 (JEP 470)

개발자 경험

  • 초보자를 위한 진입 장벽 완화 (JEP 512)
  • 향상된 프로파일링 도구 (JEP 509, 518, 520)

Java 25의 8년 LTS 지원을 통해 기업들은 안정적인 플랫폼에서 최신 기능들을 활용할 수 있게 되었으며, 이는 Java가 현대적인 소프트웨어 개발의 핵심 플랫폼으로 계속 발전할 수 있게 하는 중요한 기반이 될 것입니다.


이 문서는 OpenJDK 공식 문서와 Oracle의 공식 발표를 바탕으로 검증되었습니다. 프로덕션 환경에서 사용하기 전에는 충분한 테스트와 검증을 수행하시기 바랍니다.

검증 소스:

profile
항상 배우는 자세로 🪴

1개의 댓글

comment-user-thumbnail
2025년 9월 20일

정말 좋은 정보입니다. 바로 팔로잉 꾸~욱~

답글 달기