반응형
서론
JDK 21이 발표됨에 따라 관련 업데이트 내용 정리
JDK 17 이후 최신 LTS 버전
주요 업데이트 내용
- Record Patterns
- Pattern Matching for switch
- Virture Thread 표준화
- Sequenced Collection
- Unnamed Classes and Instance Main Methods
- Unnamed Patterns and Variables
Record Patterns
- Record 타입에 대한 destructed가 가능해졌다.
패턴 매칭
// As of Java 16
record Point(int x, int y) {}
static void printSum(Object obj) {
if (obj instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// As of Java 21
static void printSum(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
}
}
중첩 패턴
// As of Java 16
record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}
// As of Java 21
static void printColorOfUpperLeftPoint(Rectangle r) {
if (r instanceof Rectangle(ColoredPoint(Point p, Color c),
ColoredPoint lr)) {
System.out.println(c);
}
}
Pattern Matching for switch
- switch문에서 instanceOf로 체크한 Object에 대해 자동으로 형변환이 되도록 개선되었다.
// JDK 16 이전
if (obj instanceof String) {
String s = (String)obj;
... use s ...
}
// JDK 16
if (obj instanceof String s) {
... use s ...
}
// JDK 21 이전
static String formatter(Object obj) {
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;
}
// JDK 21
static String formatterPatternSwitch(Object obj) {
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();
};
}
Virture Thread 표준화
- JDK 19에서 등장했던 Virture Thread의 표준화
- JDK 20에서 Structured Concurrency 제공으로, Thread에서 동시성 관련 이슈에 제어
Virture Thread 사용 예시
@SpringBootTest
public class VirtureThreadTest {
private static final Logger log = Logger.getAnonymousLogger();
@Test
public void 가상_스레드를_확인한다() throws InterruptedException{
log.info("\nthreadName: " + Thread.currentThread().getName() + "\navailableProcessors: " + Runtime.getRuntime().availableProcessors());
final long start = System.currentTimeMillis();
final AtomicLong index = new AtomicLong();
final int count = 100;
final CountDownLatch countDownLatch = new CountDownLatch(count);
final Runnable runnable = () -> {
try {
final long indexValue = index.incrementAndGet();
Thread.sleep(1000L);
log.info("\nthreadName: " + Thread.currentThread().getName() + "\nvalue: " + indexValue);
countDownLatch.countDown();
} catch (final InterruptedException e) {
countDownLatch.countDown();
}
};
try (final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < count; i++) {
executorService.submit(runnable);
}
}
countDownLatch.await();
final long finish = System.currentTimeMillis();
final long timeElapsed = finish - start;
log.info("\nthreadName: " + Thread.currentThread().getName() + "\nRun time: " + timeElapsed);
}
}
Structured Thread 사용 예시
@SpringBootTest
public class StructuredThreadTest {
@Test
public void 중간_작업이_실패하면_모든_작업이_종료된다() {
Assertions.assertThrows(RuntimeException.class, () -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<List<String>> list = scope.fork(this::list);
Supplier<String> str = scope.fork(this::str);
list.get().forEach(System.out::println); // 찍히지 않는다.
scope.join().throwIfFailed();
assertEquals("This is String", str.get());
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
});
}
public String str() {
throw new RuntimeException();
}
public List<String> list() {
List<String> result = new ArrayList<>() ;
IntStream
.range(0, 100)
.forEach(index -> result.add("This is list_" + index));
return result;
}
}
Sequenced Collection
- 기존에 Collection의 마지막 요소에 접근하려면 list.get(list.size()-1);로 접근해야 했던 불편함이 개선되었다.
@SpringBootTest
public class SequencedCollectionsTest {
@Test
public void 마지막_요소를_가져온다() {
List<Integer> result = new ArrayList<>() ;
IntStream
.range(0, 100)
.forEach(result::add);
Assertions.assertEquals(99, result.getLast());
}
@Test
public void 현재_마지막_요소를_제거한후_마지막_요소를_가져온다() {
List<Integer> result = new ArrayList<>() ;
IntStream
.range(0, 100)
.forEach(result::add);
result.remove(99);
Assertions.assertEquals(98, result.getLast());
}
}
Unnamed Classes and Instance Main Methods
- java method 실행 시에 사용자 편의성을 위한 고안으로 다음과 같이 작성
// JDK 21 이전
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
// JDK 21
class HelloWorld {
void main() {
System.out.println("Hello, World!");
}
}
Unnamed Patterns and Variables
- 메서드 내 객체 파라미터를 참조하지 않을 경우 '_'로 선언
for (Object _ : list) { ... anyMethod(); ... }
반응형
LIST
'언어 > java' 카테고리의 다른 글
[시스템 프로그래밍] JVM 실행 흐름에 대한 코드 분석 (0) | 2024.07.17 |
---|---|
JDK 동적 프록시 (2) | 2023.12.05 |
[Java] 자바의 컬렉션(Collection) (0) | 2020.05.10 |
JAVA EE,SE,ME에 대하여 (0) | 2019.08.08 |
JDK와 JRE (0) | 2019.08.08 |