선택 심화: 프리뷰 소스 격리
필수 입문 과정을 마친 학습자가 Java 25 프리뷰 기능의 플래그, 소스 세트와 산출물 격리를 선택적으로 실험합니다.
이 장은 선택 심화 과정입니다.
Java 문법, 객체지향, 컬렉션, 예외, 파일, 네트워크와 JVM 실행 원리를 먼저 익힌 뒤 관심이 있을 때 진행하세요.
이후 핵심 장은 이 장의 프리뷰 기능을 안다고 가정하지 않으므로 건너뛰어도 자습 흐름에 문제가 없습니다.
프리뷰 기능은 완성된 Java SE 규칙이 아니라 개발자가 피드백을 제공하도록 공개한 제한적 기능입니다.
Java 25의 Stable Values, 구조화된 동시성, 기본형 패턴은 프리뷰이며 기본적으로 비활성입니다.
프리뷰 API나 문법은 다음 릴리스에서 바뀌거나 사라질 수 있습니다. Java 25 프리뷰 기능을 사용한 클래스 파일은 Java 25 런타임에서 프리뷰를 허용해 실행해야 합니다.
따라서 안정적인 애플리케이션 소스와 같은 빌드 경로에 섞지 않습니다.
프리뷰 플래그 없는 StableValue 참조
아래 소스를 기본 javac로 컴파일하면 StableValue is a preview API and is disabled by default 계열 오류가 발생합니다.
클래스가 JDK에 존재한다는 사실만으로 정식 API라고 판단할 수 없습니다.
public final class PreviewFeatureWithoutFlagFailure {
public static void main(String[] args) {
StableValue<String> value = StableValue.of();
System.out.println(value.orElseSet(() -> "preview"));
}
}컴파일 명령과 예상되는 진단의 요지는 다음과 같습니다.
javac --release 25 PreviewFeatureWithoutFlagFailure.java
# error: StableValue is a preview API and is disabled by default원칙은 프리뷰 소스에만 컴파일과 실행 플래그를 함께 적용하는 것입니다.
컴파일할 때만 플래그를 붙이면 프리뷰 클래스 파일을 실행 환경이 거부할 수 있습니다.
컴파일 옵션은 소스와 API를 허용할지 결정하고, 실행 옵션은 이미 만들어진 클래스의 로딩을 허용합니다. 서로 다른 두 프로세스의 판단이므로 컴파일 때 허용한 값이 실행기에 자동 전달되지는 않습니다. 예제 파일 이름과 public 클래스 이름을 맞추고, JDK 25의 컴파일러·실행기를 각각 확인한 뒤 두 명령을 수행합니다.
Stable Values 실행 경로
StableValue는 Java 25의 JEP 502 프리뷰 API입니다.
값이 정상적으로 설정된 뒤에는 초기화 함수를 다시 호출하지 않습니다. 초기화 함수가 예외를 던지면 값이 설정되지 않아 다음 호출에서 초기화를 다시 시도할 수 있습니다.
아래 예제는 반드시 프리뷰 플래그로 컴파일·실행합니다.
import java.util.concurrent.atomic.AtomicInteger;
public final class StableValuePreviewProbe {
public static void main(String[] args) {
StableValue<String> value = StableValue.of();
AtomicInteger calls = new AtomicInteger();
String first = value.orElseSet(() -> "value-" + calls.incrementAndGet());
String second = value.orElseSet(() -> "value-" + calls.incrementAndGet());
System.out.println("first=" + first);
System.out.println("second=" + second);
System.out.println("initializer-calls=" + calls.get());
}
}javac --enable-preview --release 25 -Xlint:preview StableValuePreviewProbe.java
java --enable-preview StableValuePreviewProbe
# first=value-1
# second=value-1
# initializer-calls=1-Xlint:preview 경고를 숨기지 않고 산출물 로그에 보존합니다.
프리뷰 사용 위치가 늘어나면 검토에서 즉시 보이게 합니다.
기본형 패턴의 프리뷰 플래그
Java 25 JEP 507은 기본형 타입 패턴과 long·float·double·boolean switch를 세 번째 프리뷰로 제공합니다.
다음 소스는 기본 컴파일에서 거부되고 프리뷰 컴파일에서 실행됩니다.
public final class PrimitivePatternPreviewProbe {
static String classify(long value) {
return switch (value) {
case 0L -> "zero";
case long number when number > 0 -> "positive:" + number;
case long number -> "negative:" + number;
};
}
public static void main(String[] args) {
System.out.println(classify(0L));
System.out.println(classify(25L));
System.out.println(classify(-7L));
}
}javac --enable-preview --release 25 -Xlint:preview PrimitivePatternPreviewProbe.java
java --enable-preview PrimitivePatternPreviewProbe
# zero
# positive:25
# negative:-7--source 25보다 --release 25를 사용해 언어와 플랫폼 API 대상을 함께 고정합니다.
JDK 25 소스 실행기는 java --enable-preview File.java처럼 --source 25를 생략해도 현재 런타임 버전을 적용합니다. CI 산출물 검사는 컴파일과 실행 단계를 분리하는 편이 명확합니다.
소스 세트와 산출물 디렉터리
안정 소스는 src/main/java, 프리뷰 실험은 src/preview/java처럼 분리하고 산출물도 build/classes/main, build/classes/preview로 나눕니다.
안정 산출물 패키징 작업이 프리뷰 산출물을 참조하지 않게 의존성 그래프를 확인합니다.
import java.nio.file.Path;
import java.util.List;
public final class PreviewPathPolicy {
private record Compilation(Path source, Path output, boolean preview) {}
static List<String> javacArguments(Compilation compilation) {
java.util.ArrayList<String> arguments = new java.util.ArrayList<>();
if (compilation.preview()) {
arguments.add("--enable-preview");
arguments.add("--release");
arguments.add("25");
arguments.add("-Xlint:preview");
} else {
arguments.add("--release");
arguments.add("25");
}
arguments.add("-d");
arguments.add(compilation.output().toString());
arguments.add(compilation.source().toString());
return List.copyOf(arguments);
}
public static void main(String[] args) {
Compilation stable =
new Compilation(
Path.of("src/main/java/App.java"), Path.of("build/classes/main"), false);
Compilation preview =
new Compilation(
Path.of("src/preview/java/Lab.java"),
Path.of("build/classes/preview"),
true);
System.out.println(javacArguments(stable));
System.out.println(javacArguments(preview));
}
}프리뷰 실험 선택 기준
- 운영 요구 사항이 아니라 학습·평가 목표로 사용합니다.
- Stable Values에서는 지연 초기화 API의 의미와 경합을 관찰합니다.
- 구조화된 동시성에서는 작업 수명과 실패·취소 모델을 실험합니다.
- 기본형 패턴은 정확한 변환과 분기 가독성을 평가합니다.
- 기능별 JEP 버전과 다음 JDK에서의 변경 사항을 기록합니다.
- 안정 산출물의 의존성과 실행 플래그에 프리뷰가 전파되지 않게 합니다.
공식 기준은 JDK 25 기능 목록과 각 JEP입니다.
오래된 블로그의 생성자나 메서드 시그니처를 복사하지 않고 현재 JDK 25 API로 컴파일합니다.
JDK 25가 LTS라면 그 안의 프리뷰도 LTS 안정성을 갖나요?
아닙니다.
LTS는 공급자의 지원 정책이고 프리뷰 기능의 명세 상태를 바꾸지 않습니다.
JDK 25가 장기간 지원되더라도 프리뷰 API는 다음 릴리스에서 변경될 수 있습니다.
운영 규칙에는 정식 기능만 사용하고 프리뷰는 격리된 실험으로 유지합니다.
연습 문제
프리뷰 여부에 따라 javac와 java 인수를 정확히 생성하세요.
안정 소스 컴파일에는 릴리스 25를 지정합니다. 프리뷰 소스 컴파일에는 프리뷰·릴리스 25·프리뷰 린트 옵션을, 해당 클래스 실행에는 --enable-preview를 넣으세요.
입력 쌍은 StableLab.java·StableLab·프리뷰 true와 Application.java·Application·프리뷰 false입니다. 두 쌍에 대해 컴파일 목록과 실행 목록을 각각 먼저 작성합니다. 이 함수가 만드는 목록은 컴파일러에 전달할 계획이며, 목록 생성 성공과 실제 JDK 25 컴파일·실행 성공을 구별합니다.
해설 보기
import java.util.List;
public final class PreviewCommandPolicySolution {
static List<String> compile(String file, boolean preview) {
if (preview) {
return List.of("javac", "--enable-preview", "--release", "25", "-Xlint:preview", file);
}
return List.of("javac", "--release", "25", file);
}
static List<String> run(String className, boolean preview) {
if (preview) {
return List.of("java", "--enable-preview", className);
}
return List.of("java", className);
}
public static void main(String[] args) {
System.out.println(compile("StableLab.java", true));
System.out.println(run("StableLab", true));
System.out.println(compile("Application.java", false));
}
}안정 코드와 프리뷰 코드의 명령 경계
Java 25 · 컴파일과 실행의 프리뷰 허용
안정 코드와 프리뷰 코드의 명령 경계
컴파일과 실행에 필요한 옵션이 다릅니다. 본문의 프로그램은 명령 인수 목록만 만들며, 컴파일러나 Java 프로세스를 실행하지 않습니다.
| 만들 명령 | 필요한 옵션 | 풀이가 하지 않는 일 |
|---|---|---|
| 안정 소스 컴파일 | --release 25 | 프로세스를 실행하거나 컴파일 결과를 확인하지 않음 |
| 프리뷰 소스 컴파일 | --enable-preview --release 25 -Xlint:preview | 실행 JDK의 버전이나 산출물 격리를 검사하지 않음 |
| 프리뷰 클래스 실행 | --enable-preview | 메인 클래스 존재·의존성·JDK 25 일치를 검사하지 않음 |
- 안정 소스 컴파일
- 필요한 옵션
--release 25- 풀이가 하지 않는 일
- 프로세스를 실행하거나 컴파일 결과를 확인하지 않음
- 프리뷰 소스 컴파일
- 필요한 옵션
--enable-preview--release 25-Xlint:preview- 풀이가 하지 않는 일
- 실행 JDK의 버전이나 산출물 격리를 검사하지 않음
- 프리뷰 클래스 실행
- 필요한 옵션
--enable-preview- 풀이가 하지 않는 일
- 메인 클래스 존재·의존성·JDK 25 일치를 검사하지 않음
PreviewCommandPolicySolution은 인수 목록을 만드는 예제입니다. Java 25 프리뷰 클래스는 Java 25 런타임과 프리뷰 허용이 필요하며, 실제 컴파일·실행 성공을 이 목록만으로 판정할 수는 없습니다.
프리뷰 쌍에는 컴파일의 세 옵션과 실행의 한 옵션을 넣습니다. 안정 쌍의 실행 목록은 java·Application뿐입니다. --release는 컴파일 대상 옵션이므로 실행 목록에 복사하지 않습니다. 디렉터리를 분리한 앞의 예제와 결합하려면 별도로 출력 경로와 실행 클래스 경로도 맞춰야 합니다.