Java 21 에 새롭게 도입되는 여러 기능들 중 인상깊은 몇가지 JEP 에 대해 공유해보고자 합니다.
읽어보면서 가장 중요한 것은 Virtual Thread와 Generational ZGC 인 것 같은데 JEP에서는 간략하게 나와 이해가 어려운 부분이 있었던 것 같습니다.
아래 글을 추가로 읽어보시는 것을 추천드립니다.
첫번째 요소 접근 | 마지막 요소 접근 | |
---|---|---|
List | list.get(0) | list.get(list.size() – 1) |
Deque | deque.getFirst() | deque.getLast() |
SortedSet | sortedSet.first() | sortedSet.last() |
LinkedHashSet | linkedHashSet.iterator().next() | // missing |
interface SequencedCollection<E> extends Collection<E> {
// new method
SequencedCollection<E> reversed();
// methods promoted from Deque
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
SequencedSet<E> reversed(); // covariant override
}
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();
}
두 개의 영역으로 분리해 메모리를 관리
기존 ZGC에서 사용하던 multi-mapped memory가 존재하지 않음
# Enable ZGC (defaults to non-generational)
$ java -XX:+UseZGC
# Use Generational ZGC
$ java -XX:+UseZGC -XX:+ZGenerational
추후 기존 ZGC는 deprecated되며 Generation ZGC가 기본 버전이 될 것이라고 함
데이터에 접근하기 쉽게 개선한 패턴
private static void singleRecordPatternOldStyle() {
Object o = new GrapeRecord(Color.BLUE, 2);
if (o instanceof GrapeRecord grape) {
System.out.println("This grape has " + grape.nbrOfPits() + " pits.");
}
}
grape.nbrOfPits()를 통해 값에 접근
private static void singleRecordPattern() {
Object o = new GrapeRecord(Color.BLUE, 2);
if (o instanceof GrapeRecord(Color color, Integer nbrOfPits)) {
System.out.println("This grape has " + nbrOfPits + " pits.");
}
}
private static void nestedRecordPattern() {
Object o = new SpecialGrapeRecord(new GrapeRecord(Color.BLUE, 2), true);
if (o instanceof SpecialGrapeRecord(GrapeRecord grape, boolean special)) {
System.out.println("This grape has " + grape.nbrOfPits() + " pits.");
}
if (o instanceof SpecialGrapeRecord(GrapeRecord(Color color, Integer nbrOfPits), boolean special)) {
System.out.println("This grape has " + nbrOfPits + " pits.");
}
}
//java16
// 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 ...
}
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);
default -> obj.toString();
};
}
static void testFooBarNew(String s) {
switch (s) {
case null -> System.out.println("Oops");
case "Foo", "Bar" -> System.out.println("Great");
default -> System.out.println("Ok");
}
}
static void exhaustiveSwitchWithBetterEnumSupport(CardClassification c) {
switch (c) {
case Suit.CLUBS -> {
System.out.println("It's clubs");
}
case Suit.DIAMONDS -> {
System.out.println("It's diamonds");
}
case Suit.HEARTS -> {
System.out.println("It's hearts");
}
case Suit.SPADES -> {
System.out.println("It's spades");
}
}
}
static void testStringEnhanced(String response) {
switch (response) {
case null -> { }
case "y", "Y" -> {
System.out.println("You got it");
}
case "n", "N" -> {
System.out.println("Shame");
}
case String s
when s.equalsIgnoreCase("YES") -> {
System.out.println("You got it");
}
case String s
when s.equalsIgnoreCase("NO") -> {
System.out.println("Shame");
}
}
}
JDK 19에서 처음 소개된 Virtual Thread는 2개의 JDK 버전을 넘어오면서 개념 정립이 완료되었습니다.
java.io.BufferedInputStream
, BufferedOutputStream
, BufferedReader
, BufferedWriter
, PrintStream
및 클래스에 사용된 내부 잠금 프로토콜에서 영향을 받을 수 있음 (I/O method 동기화 과정)Thread.setPriority(int)
method has no effect on virtual threads, which always have a priority of Thread.NORM_PRIORITY
.Thread.setDaemon(boolean)
method has no effect on virtual threads, which are always daemon threads.Thread.getAllStackTraces()
now returns a map of all platform threads rather than a map of all threads.java.net.Socket
, ServerSocket
, and DatagramSocket
are now interruptible when invoked in the context a virtual thread. Existing code could break when a thread blocked on a socket operation is interrupted, which will wake the thread and close the socket.ThreadGroup
. Invoking Thread.getThreadGroup()
on a virtual thread returns a dummy "VirtualThreads"
group that is empty.GetAllThreads
and GetAllStackTraces
functions do not return virtual threads. Existing agents that enable the ThreadStart
and ThreadEnd
events may encounter performance issues since they lack the ability to limit the events to platform threads.java.lang.management.ThreadMXBean
API supports the monitoring and management of platform threads, but not virtual threads.-XX:+PreserveFramePointer
flag has a drastic negative impact on virtual thread performance.static int count(Iterable<Order> orders) {
int total = 0;
for (Order _ : orders) // Unnamed variable
total++;
return total;
}
for (int i = 0, _ = sideEffect(); i < 10; i++) { ... i ... }
Queue<Integer> q = ... // x1, y1, z1, x2, y2, z2, ...
while (q.size() >= 3) {
var x = q.remove();
var y = q.remove();
var _ = q.remove(); // Unnamed variable
... new Point(x, y) ...
}
try { ... }
catch (Exception _) { ... } // Unnamed variable
catch (Throwable _) { ... } // Unnamed variable
switch (box) {
case Box(RedBall _), Box(BlueBall _) -> processBox(box);
case Box(GreenBall _) -> stopProcessing();
case Box(_) -> pickAnotherBox();
}