운영 중인 서비스의 JDK 버전을 물어보면 아직 17이라는 답을 제일 많이 듣습니다. 8에서 17로 넘어오면서 한 번 크게 고생한 기억이 남아 있으면 당분간 런타임에 손대기 싫어지는 것도 당연하죠. 예전에 JDK17은 어떻게 C10k를 해결했을까?를 쓸 때만 해도 가상 스레드는 아직 오지 않았는데, 그 사이 LTS가 두 번 더 지나갔습니다.
결론부터 말하자면 신규 프로젝트는 25로 시작하고, 운영 중인 17 서비스도 올리는 쪽을 추천합니다. 17에서 25로 갈 때 21을 경유할 필요는 없습니다. 중간 릴리스의 변경은 모두 누적되어 25에 들어 있기 때문입니다. 다만 실제 압박 요인은 성능이 아니라 쓰고 있는 배포판의 지원 종료 시점과 프레임워크가 요구하는 최소 버전입니다.
아래에서는 두 버전의 좌표, 사이에 최종화된 기능, 실제로 올릴 때 걸리는 지점을 차례로 살펴봅니다.
1. LTS가 무엇이고 17과 25는 어디에 서 있나
LTS(Long-Term Support)는 OpenJDK 벤더가 보안 패치와 버그 픽스를 오래 제공하기로 정한 릴리스를 말합니다. 자바는 6개월마다 새 버전을 내지만 그중 일부만 LTS로 지정됩니다. 비-LTS 릴리스는 다음 버전이 나오면 업데이트가 끊기기 때문에, 운영 서버에 올리는 버전은 사실상 LTS 중에서 고르게 됩니다.
11에서 17까지는 LTS 간격이 3년이었고(8에서 11은 그보다 길었습니다), 17 이후로는 2년으로 짧아졌습니다. 그래서 17 다음은 21, 그다음이 25입니다.
- JDK 17 GA 2021년 9월 14일
- JDK 21 GA 2023년 9월
- JDK 25 GA 2025년 9월 16일
날짜보다 중요한 건 지원 기간입니다. Oracle 공식 로드맵 기준으로 Oracle JDK 17의 Premier Support는 2026년 9월에 끝나고, 그 뒤는 2029년 9월까지의 Extended Support 구간으로 넘어갑니다. 로드맵 각주에 따르면 17의 Extended Support 수수료는 2026년 10월부터 2029년 9월까지 면제되지만, 유료 구독 자체는 필요합니다. 무료 조건(NFTC)으로 배포되던 Oracle JDK 17 공개 업데이트는 이미 2024년 10월에 종료됐습니다(로드맵 표기 End of Permissive Licensing: 2024년 10월 15일). Oracle JDK 25도 NFTC로 무료 사용이 가능하지만 기한이 있습니다. NFTC 무료 업데이트는 다음 LTS 출시 후 1년까지라, 다음 LTS인 29가 2027년 9월에 나오면 2028년 9월경 끝납니다. 그 뒤로도 계속 Oracle JDK를 쓰려면 유료 구독(Premier Support 2030년 9월, Extended Support 2033년 9월까지)이 필요합니다. 17에서 겪은 라이선스 문제는 25에서도 2~3년 뒤 반복되니, Oracle 바이너리를 무료로만 쓸 계획이라면 배포판 교체까지 같이 고려하세요.
Oracle 바이너리를 쓰지 않는다면 배포판별 일정을 각각 확인해야 합니다. 같은 17이라도 벤더마다 끝나는 시점이 꽤 다릅니다.
- Eclipse Temurin 17: 최소 2027년 10월까지 빌드가 나옵니다. 이 날짜는 하한값이라 이후 연장될 수 있습니다. Temurin 25는 최소 2031년 9월까지입니다.
- Amazon Corretto 17: EOL이 2029년 10월입니다.
- Azul Zulu 17: Azul은 LTS를 최소 8년 지원하는 정책이며 정확한 종료일은 Azul 지원 로드맵에서 확인하세요.
즉 무료 배포판을 쓰고 있다면 17 자체가 곧 끝나는 상황은 아닙니다. 대신 벤더별 편차가 크니 지금 쓰는 배포판의 로드맵 페이지를 직접 확인해 보시길 권합니다.
💡 Oracle JDK를 그대로 쓰면서 17에 머물러 있다면 라이선스 상태부터 확인하세요. java -version 출력에 Oracle이 찍히는지, 배포판 이름(Temurin, Corretto)이 찍히는지가 첫 갈림길입니다. 아래는 배포판 바이너리를 쓰는 25 환경의 출력 예시입니다. 17이면 첫 줄이 openjdk version "17.0.x" 형태로 찍힙니다.
$ java -version < 결과 > openjdk version "25" 2025-09-16 OpenJDK Runtime Environment Temurin-25+36 (build 25+36-LTS) OpenJDK 64-Bit Server VM Temurin-25+36 (build 25+36-LTS, mixed mode, sharing) # 빌드 번호와 패치 레벨은 배포판, 설치 시점에 따라 달라집니다.
2. JDK 17이 무엇을 끝냈던 버전인가
17을 다시 정리해두면 25와의 격차가 눈에 들어옵니다. 17은 새 문법을 대거 확정한 버전이었습니다. record, 텍스트 블록, switch 표현식, instanceof 패턴 매칭은 17 이전에 이미 최종화됐고, 17에서 Sealed Classes(JEP 409)가 정식이 됐습니다. switch의 패턴 매칭은 17 시점에 아직 1차 프리뷰(JEP 406)였습니다.
동시에 17은 정리를 시작한 버전이기도 합니다.
- JEP 403 - JDK 내부 API 강력 캡슐화.
--illegal-access옵션이 무효화됐습니다. 이때부터--add-opens를 붙여 버티는 코드가 늘었습니다. - JEP 411 - Security Manager 폐기 예정 표시
- JEP 407 - RMI Activation 제거, JEP 410 - 실험적 AOT/JIT 컴파일러 제거, JEP 398 - Applet API 폐기 예정
- JEP 356 - 향상된 의사난수 생성기, JEP 391 - macOS/AArch64 포트(애플 실리콘 대응), JEP 415 - 컨텍스트별 역직렬화 필터
- JEP 412 - FFM API 인큐베이터, JEP 414 - Vector API 2차 인큐베이터
17에서 인큐베이터로 들어온 FFM API는 22에서 최종화됐고, Security Manager는 24에서 영구 비활성 상태가 됐습니다. 17에서 표시만 해둔 항목의 결말이 25에 들어 있는 셈입니다.
3. 17과 25 사이에 최종화된 변화
비-LTS 릴리스에서 확정된 기능도 25에 그대로 들어 있습니다. 개발자가 체감하는 순서대로 보겠습니다.
3.1 가상 스레드 (JEP 444, JDK 21)
가상 스레드는 JVM이 직접 관리하는 경량 스레드입니다. OS 스레드 하나에 여러 개를 얹어 실행하다가, 블로킹 I/O를 만나면 JVM이 OS 스레드에서 떼어냅니다. 스레드 하나당 OS 자원을 잡아먹지 않으니, 요청당 스레드 하나 모델을 그대로 두면서 동시 접속 수를 크게 늘릴 수 있습니다.
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return null;
});
}
}
도입 초기에는 synchronized 블록 안에서 블로킹하면 캐리어 스레드가 묶이는 핀닝(pinning) 문제가 있었습니다. 그래서 ReentrantLock으로 바꾸라는 안내가 늘 따라붙었죠. 이 제약은 JEP 491(JDK 24)에서 해소됐습니다. 이제 synchronized 안에서 블로킹해도 가상 스레드가 언마운트됩니다. 25로 올라가면 기존 코드를 통째로 ReentrantLock으로 갈아엎을 이유가 줄어듭니다.
⚠️ 다만 ThreadLocal을 캐시처럼 쓰던 코드는 여전히 점검 대상입니다. 가상 스레드는 수만 개가 만들어지므로, 스레드당 무거운 객체를 물고 있으면 메모리가 그만큼 늘어날 수 있습니다. 이 자리를 대신하라고 나온 것이 25에서 최종화된 Scoped Values(JEP 506)입니다.
3.2 패턴 매칭 완성 (JEP 441, 440, JDK 21)
switch의 패턴 매칭이 21에서 최종화됐고, record 패턴도 같이 확정됐습니다. 17에서 instanceof를 줄줄이 늘어놓던 분기가 이렇게 줄어듭니다.
sealed interface Shape permits Circle, Rect {}
record Circle(double r) implements Shape {}
record Rect(double w, double h) implements Shape {}
static double area(Shape s) {
return switch (s) {
case Circle(double r) -> Math.PI * r * r;
case Rect(double w, double h) -> w * h;
};
}
Sealed 인터페이스와 조합하면 컴파일러가 모든 경우를 다뤘는지 검사해주므로 default 절이 필요 없습니다. 17에서 Sealed Classes만 받아두고 활용을 못 했다면 25에서 제값을 합니다.
3.3 컬렉션과 표준 API
- Sequenced Collections(JEP 431, 21) - 순서가 있는 컬렉션에
getFirst(),getLast(),reversed()가 공통 인터페이스로 들어왔습니다.list.get(list.size()-1)같은 관용구를 안 써도 됩니다. - FFM API 최종(JEP 454, 22) - 네이티브 메모리와 함수를 표준 API로 다룹니다. JNI와
sun.misc.Unsafe의 대체재입니다. - Stream Gatherers 최종(JEP 485, 24) - 중간 연산을 직접 만들 수 있습니다. 윈도잉, 커스텀 그룹핑을 스트림 안에서 처리합니다.
- Class-File API 최종(JEP 484, 24) - JDK가 표준 클래스 파일 파서, 생성기를 제공합니다. ASM 계열 라이브러리가 새 클래스 파일 버전을 못 따라와 빌드가 깨지던 문제의 근본 대책입니다.
- 이름 없는 변수와 패턴
_(JEP 456, 22), Markdown 문서 주석(JEP 467, 23), 다중 파일 소스 프로그램 실행(JEP 458, 22).
참고로 21과 22에서 프리뷰로 나왔던 String Templates는 최종화되지 못하고 23에서 제거됐습니다. 프리뷰 기능을 미리 써둔 코드가 있다면 이 항목이 컴파일 에러의 원인이 됩니다.
3.4 GC와 런타임
기본 GC는 17과 25 모두 G1입니다. 바뀐 쪽은 ZGC입니다. 세대별 ZGC가 JEP 439(21)로 들어왔고 JEP 474(23)에서 기본 모드가 됐으며, 비세대 모드는 JEP 490(24)에서 제거됐습니다. -XX:+UseZGC를 쓰던 곳은 25에서 자동으로 세대별 ZGC로 동작합니다.
Shenandoah도 JEP 521(25)로 세대별 모드가 정식이 됐습니다.
Project Leyden의 첫 결과물인 AOT 클래스 로딩과 링킹(JEP 483, 24)도 들어왔습니다. 애플리케이션을 한 번 훈련 실행해 캐시를 만들어두면 다음 기동부터 클래스 로딩과 링킹 결과를 캐시에서 복원해 그 비용을 줄입니다. 기동 시간 단축 폭은 애플리케이션 구성에 따라 달라지니 직접 재보셔야 합니다.
3.5 사라진 것
Security Manager는 JEP 486(JDK 24)에서 영구 비활성화됐습니다. System.setSecurityManager()를 호출하면 UnsupportedOperationException이 발생합니다.
기동 옵션 쪽은 조건을 정확히 알아둬야 합니다. -Djava.security.manager=disallow는 그대로 정상 기동합니다. 반면 disallow 외의 값을 주면 JVM이 기동에 실패합니다. 오래된 애플리케이션 서버 기동 스크립트에 =allow가 남아 있는 경우가 꽤 있으니 먼저 grep 해보시길 권합니다.
25에서는 RuntimePermission, FilePermission 같은 권한 클래스 20여 종이 제거 예정으로 표시됐습니다. 정확한 대상 목록은 JDK 25 릴리스 노트의 deprecation 항목에서 확인하세요.
sun.misc.Unsafe의 메모리 접근 메서드는 JEP 471(23)에서 제거 예정으로 표시됐고, JEP 498(24)부터 런타임 경고가 기본값입니다. 구 버전 Netty, 구 Lombok 등이 이 API를 쓰기 때문에 25로 올리자마자 이런 경고를 만날 수 있습니다.
< 결과 > WARNING: A terminally deprecated method in sun.misc.Unsafe has been called WARNING: sun.misc.Unsafe::objectFieldOffset has been called by ... WARNING: Please consider reporting this to the maintainers of ... WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
경고를 잠시 끄려면 --sun-misc-unsafe-memory-access=allow를 줍니다. 반대로 어느 라이브러리가 걸리는지 스택으로 확인하려면 =debug, 미리 실패시켜 보려면 =deny를 씁니다. 이 옵션의 기본값은 향후 릴리스에서 deny로 바뀔 예정이라, 경고를 끄는 건 임시 조치이고 라이브러리 버전을 올리는 것이 정답입니다.
플랫폼 쪽에서는 Windows 32비트 x86 포트가 JEP 479(24)에서, 나머지 32비트 x86 포트가 JEP 503(25)에서 제거됐습니다. 32비트 JVM으로 돌아가는 레거시가 남아 있다면 25는 선택지가 아닙니다.
4. JDK 25가 직접 들고 온 것
25에는 JEP 18개가 들어갔습니다. 실무에서 바로 손이 가는 항목만 추립니다.
4.1 Compact Source Files와 Instance Main Methods (JEP 512, 최종)
클래스 선언 없이 void main()만으로 실행되는 소스 파일이 정식이 됐습니다. 콘솔 입출력용 IO 클래스도 같이 들어왔습니다.
$ cat Hello.java
void main() {
IO.println("hello, 25");
}
$ java Hello.java
< 결과 >
hello, 25
운영 코드에 쓸 일은 드물지만, 스크립트나 재현 코드, 신입 교육용 예제를 만들 때 편합니다.
4.2 Module Import Declarations (JEP 511, 최종)
import module java.base; 한 줄로 모듈이 내보내는 패키지를 통째로 가져옵니다. 짧은 유틸리티나 예제 코드에서 import 목록을 줄이는 용도입니다.
4.3 Flexible Constructor Bodies (JEP 513, 최종)
생성자에서 super() 또는 this() 호출 앞에 문장을 둘 수 있게 됐습니다. 인자 검증을 부모 생성자 호출 전에 하려고 정적 헬퍼 메서드를 만들던 우회가 사라집니다.
class PositiveBox extends Box {
PositiveBox(int size) {
if (size <= 0) throw new IllegalArgumentException("size");
super(size); // JDK 25: 검증 코드를 super() 앞에 둘 수 있다
}
}
4.4 Scoped Values (JEP 506, 최종)
Scoped Value는 정해진 실행 범위 안에서만 값을 공유하는 불변 컨텍스트입니다. ThreadLocal과 달리 값을 나중에 바꿀 수 없고 범위를 벗어나면 사라지므로, 가상 스레드를 수만 개 만들어도 값이 새거나 남지 않습니다. 요청 ID나 인증 주체를 아래로 전달할 때 쓰기 좋습니다.
4.5 Compact Object Headers는 켜면 이득일까?
객체 헤더를 줄이는 기능(JEP 519)입니다. 64비트 JVM에서 압축 클래스 포인터가 켜진 기본 구성이면 헤더가 12바이트에서 8바이트로 줄어듭니다. 단 자바 객체는 8바이트 단위로 정렬되므로 객체마다 4바이트가 그대로 회수되는 것이 아니라, 정렬 경계를 넘는지에 따라 0바이트 또는 8바이트가 줄어듭니다. 공식 문서는 평균적으로 객체당 약 4바이트 절감이라고 설명하니, 대략적인 추산은 그 기준으로 하되 개별 객체는 0 또는 8바이트로 갈린다는 점을 기억하세요. 25에서 실험 단계를 벗어나 정식 기능이 됐지만 기본값은 아닙니다. 켜려면 플래그를 직접 줘야 합니다.
$ java -XX:+UseCompactObjectHeaders -jar app.jar
작은 객체를 대량으로 들고 있는 애플리케이션일수록 힙 절감 폭이 큽니다. 반대로 큰 배열이나 버퍼 위주면 차이가 거의 없습니다. 절감량은 객체 크기 분포에 따라 크게 달라지니, 켜기 전후로 실제 힙을 재본 뒤 유지 여부를 판단하세요.
4.6 AOT 명령줄 인간공학 (JEP 514)
24에서는 훈련 실행과 캐시 생성이 두 단계였는데, 25에서는 한 번에 끝납니다.
# 훈련 실행하면서 캐시 생성 $ java -XX:AOTCacheOutput=app.aot -jar app.jar # 이후 기동 시 캐시 사용 $ java -XX:AOTCache=app.aot -jar app.jar
기동 시간 개선폭은 클래스 개수와 프레임워크 구성에 좌우됩니다. 컨테이너를 자주 띄웠다 내리는 환경이라면 측정해볼 가치가 있습니다.
4.7 아직 확정되지 않은 것
운영 코드에 넣기 전에 상태를 확인해야 하는 항목도 있습니다.
- Structured Concurrency(JEP 505)는 25에서도 5차 프리뷰입니다.
--enable-preview가 필요하고 API가 또 바뀔 수 있습니다. - Vector API(JEP 508)는 10차 인큐베이터입니다. Valhalla 프로젝트에 묶여 있어 확정 시점이 미정입니다.
- Stable Values(JEP 502), PEM 인코딩 API(JEP 470), 패턴에서의 기본형 타입(JEP 507)도 프리뷰입니다.
- JFR 쪽은 CPU 시간 프로파일링(509, 실험, 리눅스 전용), 협력적 샘플링(518), 메서드 타이밍과 트레이싱(520)이 들어왔습니다.
- 보안 쪽은 Key Derivation Function API(510)가 최종화됐고, 양자내성 알고리즘 ML-KEM, ML-DSA는 24에 들어왔습니다(496, 497).
5. 17에서 25로 올릴 때 실제로 걸리는 지점
5.1 빌드 도구와 바이트코드 조작 라이브러리
업그레이드 초반에 자주 발견되는 지점 중 하나입니다. JDK 25가 만드는 클래스 파일은 major version 69입니다(17은 61). 클래스 파일을 읽거나 만드는 도구가 69를 모르면 Unsupported class file major version 69 계열 에러로 빌드가 죽습니다.
$ javac Foo.java && javap -v Foo | grep major < 결과 > major version: 69
Gradle은 공식 호환성 표 기준으로 Java 25를 실행, 툴체인 양쪽에서 지원하는 최소 버전이 9.1.0입니다.
Maven은 버전 라인부터 확인하세요. Apache Maven 공식 문서 기준으로 3.8.x 이하는 전 라인이 EOL이고, 새로 릴리스되는 플러그인은 3.9.0 이상을 요구합니다. JDK 25 관련 수정은 3.9.12에 포함됐고, 이후 3.9.x 라인이 계속 나오고 있으니 3.9 최신 패치를 쓰시면 됩니다. 자세한 내용은 maven.apache.org/docs/history.html과 3.9.12 릴리스 노트를 참고하시면 됩니다.
Lombok, ByteBuddy, ASM, Mockito, Jacoco는 각 프로젝트 릴리스 노트에서 JDK 25 지원 버전을 직접 확인한 뒤 올리세요. 이 다섯 개는 한 번에 같이 올리는 것을 추천합니다. 하나만 남겨두면 그 하나 때문에 다시 막힙니다.
5.2 Spring Boot는 어느 버전부터 되나?
Spring Boot 2.7.x의 공식 시스템 요구사항은 Java 8 이상, 21까지입니다. 25는 지원 범위 밖이라, 25로 가려면 3.x 이상이 필요하고, 여기에는 javax.*에서 jakarta.*로 바뀌는 네임스페이스 이전이 따라옵니다. 실제로는 이 작업이 JDK 업그레이드보다 손이 더 많이 갑니다.
공식 시스템 요구사항 문서 기준으로 Spring Boot 3.5는 Java 17 이상, Java 25까지 호환입니다. Spring Boot 4.x는 Spring Framework 7 기반이며 역시 Java 17 이상을 요구하고, 상위 버전 호환 범위가 더 넓습니다.
현재 2.x를 쓰고 있다면 순서를 이렇게 잡으세요.
- JDK 17을 유지한 채 Spring Boot 3.x로 이전(
jakarta네임스페이스 변경 포함) - 테스트 통과 후 JDK만 25로 교체
- 가상 스레드, AOT 캐시 같은 선택 기능은 그다음에 하나씩
⚠️ 두 가지를 한 커밋에서 같이 바꾸면 깨졌을 때 원인을 가리기 어렵습니다. 반드시 나눠서 진행하세요.
5.3 기동 옵션 정리
서비스 기동 스크립트를 열면 먼저 눈에 걸리는 옵션들이 있습니다. 항목마다 심각도가 다르니 구분해서 보세요.
# [기동 실패] =disallow 외의 값이면 JVM이 시작하지 않는다 # -Djava.security.manager=disallow 는 정상 기동한다 -Djava.security.manager=allow # [경고만] 24에서 obsolete 처리. 지정해도 무시되고 경고만 찍히며 JVM은 기동한다 -XX:-ZGenerational # [deprecated] 25에서 폐기 예정 표시. 향후 제거 대상 -XX:+UseCompressedClassPointers # [동작하지만 점검] 내부 API를 뚫어 쓰는 코드가 남아 있다는 신호 --add-opens java.base/java.lang=ALL-UNNAMED
--add-opens가 붙어 있다면 그 대상 라이브러리가 아직 JDK 내부 API에 의존한다는 뜻입니다. 25에서도 옵션 자체는 동작하지만, 이런 코드는 다음 릴리스에서 또 깨질 수 있습니다. 라이브러리를 올려 옵션을 지우는 쪽이 장기적으로 유지비가 쌉니다.
5.4 단계별로 확인하는 방법
17로 빌드한 산출물을 25 런타임에 먼저 올려보는 방법이 안전합니다. 컴파일 문제와 런타임 문제를 분리해서 볼 수 있습니다.
# 1) 17로 빌드한 jar을 25 JVM으로 실행 (런타임 호환성만 확인) $ /usr/lib/jvm/temurin-25/bin/java -jar build/libs/app.jar # 2) 문제 없으면 컴파일 타깃을 올린다 $ javac --release 25 -d out $(find src -name '*.java') # 3) 제거 예정 API 사용처를 한 번에 뽑는다 $ javac --release 25 -Xlint:deprecation,removal -d out $(find src -name '*.java')
-Xlint:removal이 뽑아주는 경고가 다음 LTS에서 실제 에러가 될 후보입니다. 업그레이드하면서 같이 정리해두면 다음 LTS인 29(2027년 9월 예정)로 갈 때 다시 고생하지 않습니다. 참고로 26, 27, 28은 비-LTS라 운영 서버 기준선으로 삼을 버전은 아닙니다.
6. 그래서 지금 올려야 하나
상황에 따라 판단이 갈리는데, 자주 마주치는 경우를 정리하면 이렇습니다.
- 신규 프로젝트: 25로 시작하세요. 고민할 이유가 없습니다.
- Oracle JDK 17을 무료로 쓰고 있다: 이미 무료 공개 업데이트가 끊긴 상태입니다. 25로 올리거나, 최소한 Temurin, Corretto 같은 무료 배포판으로 바꾸세요. 성능이 아니라 보안 패치 문제입니다.
- 무료 배포판 17을 쓰고 있다: 남은 기간이 배포판마다 다릅니다. Temurin은 최소 2027년 10월(연장 가능), Corretto는 2029년 10월, Zulu는 2029년 이후 확장 지원까지입니다. 쓰고 있는 배포판의 로드맵을 먼저 확인한 뒤 프레임워크 업그레이드 일정과 묶어 계획을 잡으세요.
- Spring Boot 2.x에 묶여 있다: JDK보다 프레임워크가 먼저입니다. 3.x 이전을 끝내고 JDK를 올리세요.
- I/O 대기가 많은 서비스: 가상 스레드로 얻는 것이 실제로 있습니다. 스레드풀 크기를 늘려가며 버티고 있었다면 25에서 구조를 단순하게 바꿀 수 있습니다.
- 32비트 JVM이나 Security Manager에 의존하는 레거시: 25로 못 갑니다. 해당 의존성을 걷어내는 일이 선행 과제입니다.
성능 수치를 기대하고 올리는 건 권하지 않습니다. 가상 스레드, 세대별 ZGC, Compact Object Headers, AOT 캐시가 주는 효과는 워크로드에 따라 크게 갈리고, 어떤 서비스에서는 차이가 거의 나지 않습니다. 올릴 이유는 지원 기간과 생태계가 요구하는 최소 버전이고, 성능은 올린 뒤에 하나씩 켜보며 챙기는 보너스로 보시면 됩니다.
7. 정리
17에서 25로 가는 길은 8에서 17로 가던 때만큼 험하지 않습니다. 모듈 시스템이나 javax 제거 같은 대공사는 그때 이미 겪었고, 이번에 남은 건 Security Manager 정리, sun.misc.Unsafe 경고 대응, 빌드 도구와 바이트코드 라이브러리 버전 올리기 정도입니다. 대신 얻는 것은 가상 스레드와 패턴 매칭, 표준 FFM API, 그리고 2030년대까지 이어지는 지원 기간입니다.
순서만 지키면 됩니다. 프레임워크 먼저, JDK 다음, 새 기능은 마지막. 17로 빌드한 산출물을 25 런타임에 올려보는 것부터 시작해 보시길 권합니다!