이끌든지 따르든지 비키든지

Software Development/Java

[Java] Java 21의 새로운 기능 톺아보기

SeongHo5 2024. 4. 17. 07:55

 

Java 17에 이은 다음 LTS 버전인 Java 21에 추가된 기능에 대해 알아보도록 하겠습니다.

 

💡LTS?
LTS란, 'Long-Term-Support'의 약자로, LTS 버전은 다른 버전보다 장기적인 지원과 보안 업데이트를 포함하여 상대적으로 긴 기간 동안 지원됩니다.

Java의 LTS 버전은 약 3년 주기로 출시되고 있습니다.

 

 

Java 21에 추가된 기능


 

총 15개의 기능이 추가되었고, 이를 4가지 카테고리로 분류할 수 있습니다.

 

Core Java Library

  • JEP 431: Sequenced Collections
  • JEP 442: Foreign Function & Memory API (Third Preview)
  • JEP 444: Virtual Threads
  • JEP 446: Scoped Values (Preview)
  • JEP 448: Vector API (Sixth Incubator)
  • JEP 453: Structured Concurrency (Preview)

 

Java Language Specification

  • JEP 430: String Templates (Preview)
  • JEP 440: Record Patterns
  • JEP 441: Pattern Matching for switch
  • JEP 443: Unnamed Patterns and Variables (Preview)
  • JEP 445: Unnamed Classes and Instance Main Methods (Preview)

 

HotSpot

  • JEP 439: Generational ZGC
  • JEP 449: Deprecate the Windows 32-bit x86 Port for Removal
  • JEP 451: Prepare to Disallow the Dynamic Loading of Agents

 

Security Library

  • JEP 452: Key Encapsulation Mechanism API

 

 

Core Java Library


 

■ Sequenced Collections

 

Java의 컬렉션 프레임워크는, 정렬된 순서를 가진 요소를 효과적으로 표현할 타입이 부족했습니다.

 

현재 컬렉션 중, List와 Deque는 순서를 정의하지만, Set이나 HashSet 등은 순서를 정의하지 않습니다.

반면, SortedSet이나 LinkedHashSet은 순서를 정의합니다.

 

이렇게 순서를 지원하는 기능이 컬렉션 타입 계층에 흩어져 있어,

API에서 일관된 콘셉트를 표현하기 어렵고, 때로는 구현에서 오류가 발생하는 문제가 있었습니다.

 

 

● 컬렉션별 요소에 접근하는 방법

 

구분 첫 번째 요소를 가져올 때 마지막 요소를 가져올 때
List list.get(0) list.get(list.size() - 1)
Deque deque.getFirst() deque.getLast()
SortedSet sortedSet.first() sortedSet.last()
LinkedHashSet linkedHashSet.iterator().next() // 없음

 

 

 

각 컬렉션별로 첫번째 또는 마지막 요소에 접근하는 방법이 일관되지 않고, 어떤 경우에는 구현이 불가능하기도 합니다.

 

이를 해결하기 위해 Sequenced Collections(순차 컬렉션) 타입이 도입되었습니다. 새로운 인터페이스는 모든 종류의 컬렉션에 대해 첫 요소와 마지막 요소 접근, 그리고 요소들의 역순 처리를 일관되게 지원할 수 있도록 설계되었습니다.

 

 

Java 21에 추가된 인터페이스

 

 

● SequencedCollection

 

public interface SequencedCollection<E> extends Collection<E> {

    SequencedCollection<E> reversed();

    default void addFirst(E e) {
        throw new UnsupportedOperationException();
    }

    default void addLast(E e) {
        throw new UnsupportedOperationException();
    }

    default E getFirst() {
        return this.iterator().next();
    }

    default E getLast() {
        return this.reversed().iterator().next();
    }

    default E removeFirst() {
        var it = this.iterator();
        E e = it.next();
        it.remove();
        return e;
    }

    default E removeLast() {
        var it = this.reversed().iterator();
        E e = it.next();
        it.remove();
        return e;
    }
}

 

 

기존의 Collection을 확장하며, 요소를 역순으로 처리할 수 있는 reversed() 메서드를 추가로 제공합니다.

 

 

● SequencedMap

 

public interface SequencedMap<K,V> extends Map<K,V> {
    // new methods
    SequencedMap<K,V> reversed();
    SequencedSet<K> sequencedKeySet();
    SequencedCollection<V> sequencedValues();
    SequencedSet<Entry<K,V>> sequencedEntrySet();
    V putFirst(K, V);
    V putLast(K, V);
    // methods promoted from NavigableMap
    Entry<K, V> firstEntry();
    Entry<K, V> lastEntry();
    Entry<K, V> pollFirstEntry();
    Entry<K, V> pollLastEntry();
}

 

 

SequencedMap은 LinkedHashMap 같은 기존의 순서를 유지하는 맵보다 더 명시적으로 순서 관리를 지원합니다.

 

firstEntry(), lastEntry(), pollFirstEntry(), pollLastEntry()와 같은 메서드들은 엔트리를 순서대로 접근하고 제거하는 기능을 지원합니다. 

 

 

● SequencedSet

 

public interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {

    SequencedSet<E> reversed();
}

 

 

SequencedSet은 LinkedHashSet 같은 구현을 사용할 때, 이미 존재하는 요소를 새로운 위치로 이동시킬 수 있습니다.

 

 

■ Virtual Threads

Virtual Thread(가상 스레드)는 Project Loom이라 불리다 Java 21에 정식 기능으로 추가되었습니다.

 

기존의 Java 스레드는 OS의 스레드를 직접 사용하는 방식이었으나, 이로 인해 자원 사용이 크고 비용이 많이 들었습니다. 가상 스레드는 이러한 문제를 해결하기 위해 JVM이 직접 스레드를 관리하고 스케줄링하는 경량 스레드입니다.

 

(Link)

 

 

Java Language Specification


 

 

String Templates (Preview)

Java에서 문자열을 구성하는 여러 방법에는 단점이 많았습니다.

 

// 읽기 어렵다.
String s = x + " plus " + y + " equals " + (x + y);


// 장황하다.
String s = new StringBuilder()
                 .append(x)
                 .append(" plus ")
                 .append(y)
                 .append(" equals ")
                 .append(x + y)
                 .toString();
                 
// String::formatString
String s = String.format("%2$d plus %1$d equals %3$d", x, y, x + y);

// String::formatted
String t = "%2$d plus %1$d equals %3$d".formatted(x, y, x + y);

 

 

문자열 보간을 활용한 새 기능을 통해 Java의 문자열 조작 기능을 현대적인 프로그래밍 언어 수준으로 확장하며, 보안과 편의성을 동시에 증진시키는 것을 목표로 합니다.

 

 

// Prior to Java 21
String title = "My Web Page";
String content = "Hello, World!";
String html = "<html><head><title>" + title + "</title></head><body><p>" + content + "</p></body></html>";


// As of Java 21
String title = "My Web Page";
String content = "Hello, World!";
String html = STR."""
    <html>
        <head>
            <title>\{title}</title>
        </head>
        <body>
            <p>\{content}</p>
        </body>
    </html>
    """;

 

 

Record Patterns

Java 16에서는 JEP 394를 통해 instanceof 연산자가 타입 패턴을 사용하는 패턴 매칭으로 확장되었습니다. 이 새로운 기능은 기존의 instanceof와 cast를 사용하는 방식을 단순화시켜 보다 간결하고 오류 가능성을 줄여줍니다.

 

// Prior to Java 16
if (obj instanceof String) {
    String s = (String)obj;
    ... use s ...
}

// As of Java 16
if (obj instanceof String s) {
    ... use s ...
}

 

 

 패턴이 매칭되면(instanceof 표현식은 참이 되면) 패턴 변수 s는 String으로 캐스트된 obj의 값으로 초기화되며, 이후 블록 내에서 사용할 수 있습니다.

 

 

Pattern Matching for switch

Record Patterns 기능에 이어 switch 문에서의 패턴 매칭도 개선되었습니다.

 

// Prior to Java 21
    String formatted = "unknown";
    if (obj instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (obj instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (obj instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (obj instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;

// As of Java 21
    return switch (obj) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> obj.toString();
    };

 

 

제한적이었던 switch문에서의 타입 검사를 위와 같은 간결한 방식으로 처리할 수 있게 되었습니다.

 

case 세분화

 

null 

 

enum constants

 

Unnamed Patterns and Variables

as

 

 

■ Unnamed Classes and Instance Main Methods

 

 

 

 

 

참고 자료:

 

 

JDK 21

JDK 21 This release is the Reference Implementation of version 21 of the Java SE Platform, as specified by JSR 396 in the Java Community Process. JDK 21 reached General Availability on 19 September 2023. Production-ready binaries under the GPL are avai

openjdk.org

 

JDK 21 and JDK 22: What We Know So Far

JDK 21, the next Long-Term Support (LTS) release since JDK 17, has reached its initial release candidate phase with a final set of 15 new features, in the form of JEPs, that can be separated into four categories: Core Java Library, Java Language Specificat

www.infoq.com

 

 

What's new for developers in JDK 21 | Red Hat Developer

Java 21 is here! Explore new features in JDK 21, including virtual threads, record patterns, and sequenced collections.

developers.redhat.com