기본형 패턴과 switch
Java 25 세 번째 프리뷰 기본형 패턴으로 `byte` 적합성, `long`·`boolean` `switch`, `record` 구성 요소 변환을 실행하고 선행 축소 변환의 정보 손실을 재현합니다.
JEP 507은 Java 25에서 패턴의 기본형 타입, instanceof, switch를 세 번째 프리뷰로 제공합니다.
int instanceof byte small은 형변환 가능 여부만 보는 것이 아니라 현재 값을 정보 손실 없이 byte로 변환할 수 있는지 검사하고 바인딩합니다.
long·float·double·boolean도 switch 선택자로 사용할 수 있습니다.
모든 소스는 프리뷰 컴파일·실행 플래그가 필요합니다.
패턴 검사와 강제 축소 변환
기본형 패턴의 목적은 안전하고 정확한 변환을 확인하는 것입니다.
아래 코드는 큰 long을 먼저 int로 형변환해 정보를 잃고 난 뒤 패턴 switch를 수행합니다.
4,294,967,297은 int 1로 잘려 출력이 wrong-positive=1이 됩니다.
public final class PrimitiveNarrowingBeforePatternBug {
static String classify(long original) {
int narrowed = (int) original;
return switch (narrowed) {
case int value when value > 0 -> "positive:" + value;
case int value -> "other:" + value;
};
}
public static void main(String[] args) {
long original = 4_294_967_297L;
System.out.println("original=" + original);
System.out.println("wrong-positive=" + classify(original).substring("positive:".length()));
}
}원칙은 원래 넓은 타입을 패턴 검사 대상으로 유지하고 instanceof int converted처럼 정확한 변환이 성공했을 때만 좁은 바인딩을 사용하거나 long 분기를 유지하는 것입니다.
instanceof 기본형 패턴
전통적으로 범위 확인 뒤 형변환을 별도 작성해야 했습니다.
프리뷰 패턴은 현재 int가 byte로 정확히 표현될 때만 바인딩을 만듭니다.
public final class ExactBytePatternProbe {
static String encode(int value) {
if (value instanceof byte exact) {
return "byte:" + exact;
}
return "int:" + value;
}
public static void main(String[] args) {
System.out.println(encode(127));
System.out.println(encode(128));
System.out.println(encode(-128));
System.out.println(encode(-129));
}
}관찰 결과 127과 -128만 byte 분기를 사용합니다.
instanceof byte 검사 형태도 가능하지만 바인딩 형태가 형변환 중복을 없앱니다.
정확성 규칙은 소스 타입, 대상 타입, 실행 값에 따라 달라지므로 경계값 표로 확인합니다.
javac --enable-preview --release 25 -Xlint:preview ExactBytePatternProbe.java
java --enable-preview ExactBytePatternProbe
# byte:127
# int:128
# byte:-128
# int:-129long·boolean switch 분기
Java 25 프리뷰는 이전 switch 선택자 제한을 넓힙니다.
상수 레이블 타입은 선택자와 맞춰 0L처럼 씁니다.
boolean switch는 삼항 연산자보다 여러 문장이 필요한 분기를 식으로 구성할 수 있습니다.
public final class ExpandedPrimitiveSwitch {
static String bucket(long value) {
return switch (value) {
case 0L -> "zero";
case 1L -> "one";
case long number when number > 1_000_000_000L -> "large";
case long number when number > 0 -> "positive";
case long ignored -> "negative";
};
}
static String access(boolean loggedIn) {
return switch (loggedIn) {
case true -> "member";
case false -> "guest";
};
}
public static void main(String[] args) {
System.out.println(bucket(0L));
System.out.println(bucket(5_000_000_000L));
System.out.println(bucket(-3L));
System.out.println(access(true));
System.out.println(access(false));
}
}일반 case long을 가드가 있는 case보다 앞에 두면 뒤 case에는 도달할 수 없습니다.
안정 패턴 switch에서 배운 위에서 아래 선택 규칙이 기본형 패턴에도 적용됩니다.
record 패턴의 변환 규칙
record 구성 요소가 double이어도 현재 값을 int로 정확히 변환할 수 있으면 int whole 패턴과 일치합니다.
소수부가 있거나 범위를 벗어나거나 표현 손실이 발생하는 값은 대체 경로인 double 패턴으로 갑니다.
public final class PrimitiveRecordPatternConversion {
private record Measurement(double value) {}
static String render(Measurement measurement) {
return switch (measurement) {
case Measurement(int whole) -> "whole:" + whole;
case Measurement(double decimal) -> "decimal:" + decimal;
};
}
public static void main(String[] args) {
System.out.println(render(new Measurement(25.0)));
System.out.println(render(new Measurement(25.5)));
System.out.println(render(new Measurement(3_000_000_000.0)));
}
}정확한 변환 실험표
기본형 변환은 단순 최솟값·최댓값 범위만이 아니라 부동소수점이 정수를 정확히 표현하는지, NaN·무한대·부호 있는 0을 어떻게 다루는지 확인해야 합니다. 운영 파서를 프리뷰 패턴 하나로 바꾸기 전 기존 입력 검사 의미와 비교합니다.
public final class PrimitivePatternBoundaryTable {
static String asInt(double value) {
if (value instanceof int exact) {
return "int:" + exact;
}
return "double:" + value;
}
public static void main(String[] args) {
double[] values = {
0.0,
-0.0,
42.0,
42.25,
Integer.MAX_VALUE,
(double) Integer.MAX_VALUE + 1,
Double.NaN,
Double.POSITIVE_INFINITY
};
for (double value : values) {
System.out.println(asInt(value));
}
}
}예상 산출물에 부동소수점 텍스트 전체를 고정하기보다 어느 case가 int인지 표로 기록합니다.
프리뷰 명세가 다음 릴리스에서 바뀌면 같은 점검 프로그램을 다시 실행합니다.
적용 판단
- 수치 파서와 직렬화 경계의 명시적 입력 검사를 대체하기 전에 오류 메시지 요구 사항을 확인합니다.
- 정확한 변환 분기가 기존 형변환의 절삭·반올림과 다른지 비교합니다.
long·booleanswitch가 복잡한if보다 실제로 읽기 좋은지 검토합니다.- 안정 산출물에는 프리뷰 문법을 넣지 않고 실험 결과만 설계 문서에 반영합니다.
- JDK 26의 네 번째 프리뷰에서 변화한 명세와 마이그레이션을 다시 확인합니다.
instanceof 기본형 패턴이 일치하면 모든 수치 변환이 안전한가요?
해당 소스 값을 대상 타입으로 정확하게 변환할 수 있다는 뜻입니다. 업무 범위, 단위, 오버플로 이후 이미 손실된 값까지 보장하지 않습니다. 원본을 먼저 형변환하거나 계산에서 오버플로가 난 뒤 검사하면 패턴은 잃어버린 정보를 복구하지 못합니다.
연습 문제
0, 양수 int 범위, int를 넘는 양수, 음수를 분리하세요.
원본 long을 미리 형변환하지 않습니다.
해설 보기
public final class LongMinuteClassificationSolution {
static String classify(long minutes) {
return switch (minutes) {
case 0L -> "zero";
case int exact when exact > 0 -> "compact:" + exact;
case long value when value > 0 -> "large:" + value;
case long value -> "invalid:" + value;
};
}
public static void main(String[] args) {
System.out.println(classify(45L));
System.out.println(classify((long) Integer.MAX_VALUE + 1));
System.out.println(classify(-1L));
}
}종료 기준은 compact:45, large:2147483648, invalid:-1이며 컴파일·실행 모두 프리뷰 플래그를 사용합니다.