JDK 15 핵심 기능 — Sealed 클래스와 ZGC 프로덕션 준비 완료

Sealed Classes (Preview)

Sealed Classes(JEP 360)는 어떤 클래스가 자신을 상속할 수 있는지 명시적으로 제한하는 기능입니다. Java의 상속 체계에 “허가 목록”을 도입한 것입니다.

아파트 출입 통제에 비유하면, 기존 public 클래스는 누구나 입장 가능한 건물이고, final 클래스는 아예 출입 금지인 건물입니다. Sealed 클래스는 등록된 세대원만 출입할 수 있는 건물입니다.

// === Sealed 클래스: permits로 허용된 하위 클래스 명시 ===
sealed interface Shape permits Circle, Rectangle, Triangle {}

// final: 더 이상 상속 불가
record Circle(double radius) implements Shape {
    double area() {
        return Math.PI * radius * radius;
    }
}

// final: Record는 암묵적으로 final
record Rectangle(double width, double height) implements Shape {
    double area() {
        return width * height;
    }
}

// non-sealed: 다시 개방 — 누구나 Triangle을 상속 가능
non-sealed class Triangle implements Shape {
    private final double base;
    private final double height;

    Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    double area() {
        return 0.5 * base * height;
    }
}

public class SealedClassDemo {
    // Sealed 클래스의 장점: 모든 하위 타입을 알고 있으므로
    // 컴파일러가 분기 누락을 감지할 수 있음
    static String describe(Shape shape) {
        if (shape instanceof Circle c) {
            return "원(반지름=" + c.radius() + ", 넓이=" +
                   String.format("%.2f", c.area()) + ")";
        } else if (shape instanceof Rectangle r) {
            return "사각형(" + r.width() + "x" + r.height() + ", 넓이=" +
                   String.format("%.2f", r.area()) + ")";
        } else if (shape instanceof Triangle t) {
            return "삼각형(넓이=" + String.format("%.2f", t.area()) + ")";
        }
        // Sealed이므로 이 외의 Shape 구현체는 없음
        throw new AssertionError("알 수 없는 도형");
    }

    public static void main(String[] args) {
        Shape circle = new Circle(5.0);
        Shape rect = new Rectangle(3.0, 4.0);
        Shape tri = new Triangle(6.0, 3.0);

        System.out.println(describe(circle));
        System.out.println(describe(rect));
        System.out.println(describe(tri));
        // 출력:
        // 원(반지름=5.0, 넓이=78.54)
        // 사각형(3.0x4.0, 넓이=12.00)
        // 삼각형(넓이=9.00)
    }
}

Sealed 클래스의 하위 클래스는 반드시 세 가지 중 하나를 선택해야 합니다.

키워드의미
final상속 완전 차단
sealed자신도 허용 목록 지정 (계층 연장)
non-sealed다시 개방 (기존 클래스처럼 자유 상속)

Sealed Classes는 이후 Java 17(LTS)에서 정식 확정되며, Java 21의 Pattern Matching for switch와 결합하면 exhaustive switch(모든 경우 커버 보장)가 가능해집니다.

Text Blocks 정식 확정

Java 13(First Preview) → Java 14(Second Preview)를 거쳐 Java 15에서 정식 기능(JEP 378)이 되었습니다. 더 이상 --enable-preview 플래그가 필요 없습니다.

정식 확정된 Text Blocks의 주요 기능을 정리합니다.

public class TextBlockFinal {
    public static void main(String[] args) {
        // === 1. SQL 쿼리 작성 ===
        String sql = """
                SELECT u.name, u.email, o.total
                FROM users u
                JOIN orders o ON u.id = o.user_id
                WHERE o.status = 'COMPLETED'
                  AND o.total > 10000
                ORDER BY o.total DESC
                """;
        System.out.println("SQL:");
        System.out.println(sql);

        // === 2. formatted()와 결합 — 동적 값 삽입 ===
        String name = "홍길동";
        int minTotal = 50000;
        String dynamicSql = """
                SELECT * FROM orders
                WHERE customer_name = '%s'
                  AND total >= %d
                """.formatted(name, minTotal);
        System.out.println("동적 SQL:");
        System.out.println(dynamicSql);

        // === 3. 이스케이프 시퀀스 ===
        // \s: 후행 공백 보존 (공백 한 칸)
        // \(줄 끝): 줄바꿈 방지
        String poem = """
                봄이 오면\s\s\
                산에 들에\s\s\
                꽃이 핍니다.
                """;
        System.out.println("한 줄로 연결:");
        System.out.println(poem);
        // 출력: 봄이 오면  산에 들에  꽃이 핍니다.

        // 출력:
        // SQL:
        // SELECT u.name, u.email, o.total
        // FROM users u
        // JOIN orders o ON u.id = o.user_id
        // WHERE o.status = 'COMPLETED'
        //   AND o.total > 10000
        // ORDER BY o.total DESC
        //
        // 동적 SQL:
        // SELECT * FROM orders
        // WHERE customer_name = '홍길동'
        //   AND total >= 50000
        //
        // 한 줄로 연결:
        // 봄이 오면  산에 들에  꽃이 핍니다.
    }
}

Hidden Classes (JEP 371)

Hidden Classes는 프레임워크와 라이브러리가 런타임에 생성하는 클래스를 위한 기능입니다. 일반 애플리케이션 코드에서 직접 사용할 일은 드물지만, JVM 생태계에 중요한 변화입니다.

핵심 특징은 다음과 같습니다.

  • 다른 클래스에서 이름으로 참조할 수 없음 (발견 불가능)
  • 독립적으로 언로드 가능 → 메모리 효율 향상
  • Lookup.defineHiddenClass()로 생성

프록시 패턴, Lambda 메타팩토리 등 프레임워크 내부에서 동적 클래스를 생성할 때 기존 Unsafe.defineAnonymousClass()를 대체합니다. Spring, Hibernate 등의 프레임워크가 내부적으로 전환하고 있습니다.

ZGC 프로덕션 레디 (JEP 377)

Java 11에서 실험적으로 시작된 ZGC가 4년 만에 프로덕션 레디로 승격되었습니다. 더 이상 -XX:+UnlockExperimentalVMOptions 플래그가 필요 없습니다.

# Java 15 이전: 실험적 플래그 필요
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -jar app.jar

# Java 15 이후: 바로 사용 가능
java -XX:+UseZGC -jar app.jar

ZGC의 프로덕션 레디 성능 수치입니다.

지표G1 (기본)ZGC
최대 GC 중단 시간수십~수백ms1~2ms
평균 GC 중단 시간~50ms0.5ms 미만
지원 힙 크기수십GB최대 16TB
처리량 오버헤드기준선약 5~15%

ZGC는 지연 시간(latency)이 중요한 서비스에 적합합니다. 실시간 거래 시스템, 게임 서버, 대화형 웹 서비스 등에서 GC 중단으로 인한 지연 스파이크를 제거합니다. 반면 배치 처리처럼 처리량(throughput)이 중요한 경우에는 G1이 여전히 유리할 수 있습니다.

Shenandoah GC 프로덕션 레디 (JEP 379)

Red Hat이 주도한 Shenandoah GC도 동시에 프로덕션 레디로 승격되었습니다. ZGC와 마찬가지로 저지연을 목표로 하지만, 접근 방식이 다릅니다.

특성ZGCShenandoah
출처OracleRed Hat
중단 시간1~2ms10ms 미만
색상 포인터사용 (colored pointers)미사용 (brooks pointers)
최대 힙16TB수TB

두 GC 모두 프로덕션에서 사용 가능하므로, 실제 워크로드로 벤치마크 후 선택하는 것을 권장합니다.

# Shenandoah 활성화
java -XX:+UseShenandoahGC -jar app.jar

# GC 로그로 성능 비교
java -XX:+UseZGC -Xlog:gc*:file=zgc.log -jar app.jar
java -XX:+UseShenandoahGC -Xlog:gc*:file=shenandoah.log -jar app.jar

Nashorn JavaScript 엔진 제거 (JEP 372)

Java 8에서 도입된 Nashorn JavaScript 엔진이 제거되었습니다. Java 11에서 Deprecated 경고가 나왔고, Java 15에서 완전히 삭제되었습니다.

대안은 GraalVM의 JavaScript 엔진입니다. GraalVM은 Java뿐 아니라 JavaScript, Python, Ruby 등 다국어를 지원하는 런타임이며, Nashorn보다 성능이 우수합니다.

기존에 ScriptEngine으로 Nashorn을 사용하던 코드가 있다면, GraalJS로 마이그레이션이 필요합니다.

정리

Java 12부터 15까지의 프리뷰 기능 진행 과정을 종합하면 다음과 같습니다.

기능JDK 12JDK 13JDK 14JDK 15정식
Switch ExpressionsPreview개선(yield)정식-JDK 14
Text Blocks-Preview2nd Preview정식JDK 15
Records--Preview2nd PreviewJDK 16
Pattern Matching (instanceof)--Preview2nd PreviewJDK 16
Sealed Classes---PreviewJDK 17

JDK 12~15는 “미리보기 → 피드백 반영 → 정식 확정”이라는 Java의 새로운 개발 프로세스가 자리 잡은 전환기입니다. 6개월 릴리스 주기와 프리뷰 기능 제도 덕분에, 커뮤니티 피드백을 반영한 완성도 높은 기능이 점진적으로 안착했습니다.

프로덕션에서 Java 11 LTS를 사용 중이라면, 이 기능들은 Java 17 LTS로 업그레이드할 때 한꺼번에 누릴 수 있습니다. Records, Pattern Matching, Sealed Classes, Text Blocks — 이 네 가지만으로도 코드량이 눈에 띄게 줄어듭니다.

이 글이 도움이 되었나요?