자바(SE)

[JDK] 버전별 특징 - JDK21

  • -

JDK18 ~ JDK20은 STS로 확정된 기능이 거의 없이 지나갔다. 드디어 2023년 9월 19일 LTS인 JDK21이 다양한 기능을 포함하고 발표되었다.

 

문법적인 변화

 

JEP 441: Pattern Matching for switch

이제 switch case 문장에서 단순한 값 뿐 아니라 타입, null 여부까지 판단할 수 있게 되었다. 여기서 패턴이라 특정한 형태나 구조를 가진 데이터를 찾아내기 위한 개념으로 생각할 수 있다.  기존의 switch 문장이 int, String 등으로 단순히 값이 같은지를 비교했다면 이제 Object를 파라미터로 받아서 타입 기반으로 처리하거나 when 키워드를 이용해서 조건을 추가할 수도 있게 되었다.

// if 문을 이용한 타입 확인 및 활용
static String formatter(Object obj) {
    String formatted = "unknown";
    if (obj instanceof Integer i) {                   // Integer라면 i로 형변환해서 사용
        formatted = String.format("int %d", i);
    } else if (obj instanceof Long l) {
        formatted = String.format("long %d", l);
    } 
    return formatted;
}
// 타입 패턴의 예
static String formatterSwitch(Object obj) {
    return switch (obj) {
        case Integer i -> String.format("int %d", i); // Integer라면 i로 형변환해서 사용
        case Long l -> String.format("long %d", l);
        default -> "unknown";
    };
}

// 복합 조건 활용: 조건을 연결하기 위해 when 연산자 사용
static void checkNumber(Object obj) {
    switch (obj) {
        case Integer i when i % 2 == 0 -> System.out.println("int(짝수)");
        case Integer i when i % 2 == 1 -> System.out.println("int(홀수)");
        case Long l -> System.out.println("long");
        case null, default -> System.out.println("null");
    }
}

 

JEP 440: Record Patterns

Record Patterns 기능은 JavaScript의 Destructuring과 유사한 기능으로 Record의 타입을 비교하면서 바로 record의 value들을 분해해서 사용할 수 있게 되었다.

record Person(String name, int age) {}

Person person = new Person("Alice", 30);

// 레코드 패턴을 사용하여 이름과 나이를 추출
if (person instanceof Person(var name, var age)) {
    System.out.println("이름: " + name + ", 나이: " + age);
}

 

JEP 431: Sequenced Collections

Sequenced Collection은 순서를 가져서 정렬할 수 있는 Collection들에 대해서 처음, 마지막, 정렬, 역정렬에 대한 표준 API를 제공해서 기존의 Collection에 대한 문제점을 보완하기 위해서 추가된 interface들이다.

Collection Framework의 구조: 출처: https://docs.oracle.com/en/java/javase/21/core/img/sequencedcollectiondiagram20220216.jpg

interface에 선언된 메서드들은 default 메서드로 구현되어있다.

정렬 가능한 API들을 통해서 맨 처음 요소와 맨 마지막 요소를 가져오는 방법들을 기존 API와 Sequenced Collection의 경우를 비교해서 살펴보자.

  기존 Sequenced Collection
First Element LastElement FirstElement LastElement
List list.get(0) list.get(list.size()-1) list.getFirst() list.getLast()
Deque deque.getFirst() deque.getLast() deque.getFirst() deque.getLast()
SortedSet set.first() set.last() set.getFirst() set.getLast()
SortedMap map.firstKey() map.lastKey() map.firstEntry() map.lastEntry()

Map 계열은 어차피 살짝 다르긴 하지만 SequencedCollection의 하위 구조들은 동일한 구조로 맨 처음과 마지막 요소를 가져올 수 있게 되어 일관성 있는 프로그래밍이 가능해졌다.

인터페이스들에 선언된 메서드들이 직관적이기 때문에 딱히 사용해보지 않고 이름만 살펴봐도 느낌이 올것 같다.

public interface SequencedCollection<E> extends Collection<E> {
    SequencedCollection<E> reversed();
    default void addFirst(E e) {    }
    default void addLast(E e) {    }
    default E getFirst() {    }
    default E getLast() {    }
    default E removeFirst() {    }
    default E removeLast() {    }
}

public interface SequencedMap<K, V> extends Map<K, V> {
    SequencedMap<K, V> reversed();
    default Map.Entry<K,V> firstEntry() {    }
    default Map.Entry<K,V> lastEntry() {    }
    default Map.Entry<K,V> pollFirstEntry() {   }
    default Map.Entry<K,V> pollLastEntry() {    }
    default V putFirst(K k, V v) {    }
    default V putLast(K k, V v) {    }
    default SequencedSet<K> sequencedKeySet() {   }
    default SequencedCollection<V> sequencedValues() {    }
    default SequencedSet<Map.Entry<K, V>> sequencedEntrySet() {    }
}

SequencedSet은 SequencedCollection을 상속받았고 특별한 내용은 없다.

 

Virtual Thread

최근에 추가된 기능 중 가장 주목받는 기능은 Virtual Thread이다. Virtual Thread는 기존의 스레드를 대체하는 개념은 아니며 IO 상황에서 블로킹을 유발하지 않는 아주 가벼운 스레드이지만 기존의 스레드를 상속 받기 때문에 기본적인 사용법은 유사하다.

// 1. 직접 virtual thread 만들기
Thread virtualThread = Thread.startVirtualThread(() -> {
    System.out.println("Virtual Thread 1");
});

// 2. 일반 Runnable을 Virtual Thread로 실행하기
virtualThread = Thread.ofVirtual().start(() -> System.out.println("Virtual Thread 2"));
        
// 3. ExecutorService를 이용한 Virtual Thread 실행
Runnable runnable = ()-> System.out.println("Hi Virtual Thread");
ExecutorService eService = Executors.newVirtualThreadPerTaskExecutor();
IntStream.range(0, 3).forEach(i -> eService.submit(runnable));

https://goodteacher.tistory.com/775

 

'자바(SE)' 카테고리의 다른 글

Virtual Thread  (2) 2024.09.21
[Stream] 스트림의 병렬 처리  (0) 2024.07.08
[Thread] 05. 스레드 풀  (1) 2024.07.07
[Thread] 04. 멀티 스레드와 Collection  (0) 2024.07.06
[Thread] 03.데이터의 공유와 동기화  (0) 2024.07.05
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.