Java 14

 

JEP 361: Switch Expressions

- Java 12-13 에서 preview feature 였음. Java 14 에서 standard 로 변경

String result = switch (day) {
            case "M", "W", "F" -> "MWF";
            case "T", "TH", "S" -> "TTS";
            default -> {
                if(day.isEmpty())
                    yield "Please insert a valid day.";
                else
                    yield "Looks like a Sunday.";
            }
 
        };

 

JEP 305: instanceof 패턴 매칭

- preview feature

- if (obj instanceof SomeType) 후 if 블럭에서 (SomeType) obj 캐스팅 불필요:

before:

if (obj instanceof SomeType) {
	SomeType someType = (SomeType) obj;
	someType.doSomething();
}

after:

if (obj instanceof SomeType) {
    obj.doSomething();
}

 

JEP 358: NullPointerException 메시지 개선

- 정확히 어디서 null 참조가 발생했는지 알기 쉽게 표시.

- 메서드 체이닝 코드 디버깅에 있어 특히 편해질 것으로 보임.

before:

String name = someInstance.getValue().toString();
 
//Stacktrace
Exception in thread "main" java.lang.NullPointerException
    at NullPointerExample.main(NullPointerExample.java:5)

after:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "SomeValue.toString()" because the return value of "something.getValue()" is null
    at NullPointerExample.main(NullPointerExample.java:4)

 

JEP 359: Records

- preview feature

- 순수 데이터만 담는 클래스.

- 키워드 class 대신 record 를 사용하며, 아래와 같이 선언함:

record Car(String name, String manufacturer) {}

- 컴파일 시 final 클래스가 되며, java.lang.Record 를 상속. (enum 과 유사.)

- 함께 선언한 필드는 모두 final이 되며, 값을 대입하는 public 생성자가 자동으로 생성됨:

public Car(String name, String manufacturer) {
	this.name = name;
	this.manufacturer = manufacturer;
}

- 필드의 getter 메서드도 자동으로 생성됨.

- toString, hashcode, equals 로 자동으로 오버라이딩하며, 필드 값을 기준으로 같은 결과를 반환. 

- 생성자에 사용된 필드 외에 다른 인스턴스 필드를 선언할 수 없음.

- 인스턴스 메서드 선언 가능.

- interface 구현 가능.

- static 필드, 메서드는 선언 가능.

- 생성자 오버로딩 가능.

- 자동 생성된 기본 생성자 변경 가능. 이 때 생성자 파라미터 생략 가능:

record Car(String name, String manufacturer) {
	public Car {	// 파라미터 생략 가능. name, manufacturer 이 숨겨져 있다.
    	// 파라미터 할당문 생략 가능. 컴파일러가 자동 생성.
    }
}

- java.lang.Class 에 isRecord, getRecordComponents 가 추가됨. isRecord는 이 클래스가 record 타입인지 확인하고, getRecordComponents는 record 필드를 가져옴.

 

JEP 368: Text Blocks

- preview feature (second preview)

- Java 13 에서 등장한 Text Blocks 에 새로운 이스케이프 2 개 추가

- \ (백슬래시) : 자동 줄바꿈을 방지함:

String inline = """
		1\
                2\
                3\
                """;
System.out.println(inline); // "123"

- \s: 공백을 유지함. Text Blocks 에서는 문자열이 자동으로 stripped되기 때문에, 기본적으로 앞뒤 공백이 제거됨. 공백을 유지하고 싶은 경우 사용.

 

JEP 343: Packing Tool (jpackage)

- incubator

- 자바 어플리케이션 패키징을 손쉽게 하기 위해 사용.

- 플랫폼에 맞는 패키징을 돕는다. (Linux: deb, rpm / macOS: pkg, dmg / Windows: msi, exe)

 

JEP 345: NUMA-Aware Memory Allocation for G1

- Non-Uniform Memory Access (NUMA) 는 멀티프로세싱 시스템에서의 멀티프로세서 클러스터링 아키텍처로, 각 프로세스가 독립적인 로컬 메모리를 보유하도록 하여 성능 향상을 도모한다. 프로세서와 그 프로세서의 메모리(로컬 메모리) 로 하나의 NUMA node를 구성하며, 프로세서가 자신의 node의 메모리에 빠르게 접근할 수 있다. 외부 node로의 접근은 상대적으로 느리며, 그 속도는 node의 거리가 멀수록 더 느리다.

- Java 14 에서는 G1이 NUMA를 인식하여 새로 메모리를 할당할 때 현재 쓰레드가 위치한 같은 NUMA node에 가용 공간이 있는지를 먼저 찾고, 없으면 가장 인접한 node를 검색하는 방식으로 NUMA 아키텍처의 성능 이점을 활용하도록 한다.

- 다음 파라미터로 활성화함:

+XX:+UseNUMA

- 위 파라미터를 지정하면 JVM이 초기화될 때 전체 NUMA nodes에 regions를 분포하도록 한다.

 

JEP 349: JFR Event Streaming

- JFR 이벤트를 수신할 수 있는 API 를 제공.

- in-process, out-of-process 어플리케이션 모두에 사용 가능.

- jdk.jfr.consumer 패키지 사용.

- CPU 사용률과 모니터 락 경합 이벤트를 10ms 주기로 수신하는 예시 코드:

try (var rs = new RecordingStream()) {
  rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
  rs.enable("jdk.JavaMonitorEnter").withThreshold(Duration.ofMillis(10));
  rs.onEvent("jdk.CPULoad", event -> {
    System.out.println(event.getFloat("machineTotal"));
  });
  rs.onEvent("jdk.JavaMonitorEnter", event -> {
    System.out.println(event.getClass("monitorClass"));
  });
  rs.start();
}

 

JEP 352: Non-Volatile Mapped Byte Buffers

- java.nio.MappedByteBuffer 가 non-volatile memory (NVM) 의 파일을 로드 처리할 수 있도록 함.

 

JEP 364: ZGC on macOS

- experimental

- macOS에서 ZGC 지원.

- macOS에서 메모리 멀티 매핑 지원.

- 인접하지 않은 메모리 reservations 지원.

 

JEP 365: ZGC on Windows

- experimental

- Windows에서 ZGC 지원.

- Windows 10 지원.

- WIndows Server version < 1803 미지원.

 

JEP 370: Foreign-Memory Access API

- incubator

- 새로운 native memory 접근 API 추가.

- 자바 어플리케이션의 힙 메모리 사용은 메모리 효율성, (상대적으로)낮은 성능, GC 등의 이슈가 있음. 

- 이에 때에 따라서 외부 메모리(native memory)에 접근할 필요가 있는데, 기존 접근 방법은 ByteBuffer API, Unsafe API 두 가지가 있음.

- ByteBuffer API는 native memory 할당을 가능하게 하지만, 가용 메모리가 최대 2 기가라는 점과, 메모리 해제를 GC가 책임져야 한다는 한계가 있음. 때문에 잘못된 방법으로 API를 사용하면 메모리 릭이 발생할 수 있고 OOM으로 연결됨.

- Unsafe API는 메모리 관리에 굉장히 효율적일 수 있지만, 잘못 사용하면 JVM 크래시를 일으킬 수 있고, 표준 API가 아니라는 단점이 있음.

- Java 14 는 native memory 접근을 위한 세 가지 추상화를 제공: MemorySegment, MemoryAddress, MemoryLayout.

- MemorySegment: 힙 또는 native memory에 연속된 메모리 공간을 할당함. 다음과 같이 사용할 수 있음:

MemorySegment memorySegment = MemorySegment.allocateNative(200);  // 200 바이트의 native memory 할당.
MemorySegment memorySegment = MemorySegment.ofArray(new long[100]);  // 자바 힙 메모리 segment.
MemorySegment memorySegment = MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect(200));  // buffer memory segment.

mapped memory file에도 사용할 수 있음. (mapped memory segment):

MemorySegment memorySegment = 
	MemorySegment.mapFromPath(Path.of("/tmp/memory.txt"), 200, FileChannel.MapMode.READ_WRITE);

 

memory segment는 현재 쓰레드에 묶임. 다른 쓰레드에 있는 memory segment에 접근하려면 acquire 메서드를 통해 접근 권한을 획득해야 함.

memory segment는 JVM 안정성을 위해 그 접근에 있어 두 가지 바운더리가 있음:

Spatial boundary: 공간적 경계. 접근 가능한 범위가 정해져 있어, 이 범위 밖의 메모리에 접근 시도하면 exception 발생.

Temporal boundary: 시간적 경계. 생성 및 사용되고, 더 이상 사용되지 않으면 closed된다. closed된 영역에 접근 시도하면 exception 발생.

 

- MemoryAddress: memory segment의 memory offset. 메모리의 데이터를 검색하거나 할 때 사용됨:

MemoryAddress address = MemorySegment.allocateNative(100).baseAddress();

- MemoryLayout: memory segment의 내용을 제공. 특히 메모리를 점유하는 요소의 사이즈를 제공하여 메모리가 요소에 어떤식으로 분산할지 정의할 수 있음.

int numberOfPoints = 10;
MemoryLayout pointLayout = MemoryLayout.ofStruct(
  MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("x"),
  MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("y")
);
SequenceLayout pointsLayout = 
  MemoryLayout.ofSequence(numberOfPoints, pointLayout);

- MemoryHandles: MemorySegment로 할당한 메모리를 사용함:

long value = 10;
MemoryAddress memoryAddress = MemorySegment.allocateNative(8).baseAddress();
VarHandle varHandle = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder());
varHandle.set(memoryAddress, value);
 
assertThat(varHandle.get(memoryAddress), is(value));

- 이 외에 다양한 MemoryLayouts가 존재함: ValueLayout, SequenceLayout, GroupLayout.

 

 

출처: 

https://www.journaldev.com/37273/java-14-features

https://dzone.com/articles/a-first-look-at-records-in-java-14

https://openjdk.java.net/jeps/349

https://www.baeldung.com/java-foreign-memory-access

'Java > Core' 카테고리의 다른 글

Java 13 간략히 정리  (0) 2020.07.16
Java 12 간략히 정리  (0) 2020.07.15
Java 11 간략히 정리  (0) 2020.07.15
Java 10 간략히 정리  (0) 2020.07.15
IO, NIO, NIO2  (0) 2020.02.26

+ Recent posts