Engineering
Big things in JDK 10
2018년 12월 7일
원문에서 보기 ↗JDK 10
2018년 3월 20일에 발표된 JDK 10에서 추가된 전체 기능은 아래의 JDK Enhancement Proposals(JEPS)에서 살펴볼 수 있습니다.
http://openjdk.java.net/projects/jdk/10/
약 109개의 신규 기능들로 이루어져있으며, 대표적으로 var를 사용한 지역변수 타입 추론, Parallel GC, 개별 쓰레드로 분리된 Stop-The-World 등이 있습니다.
Big features
대표적인 몇 가지 신규 feature들은 아래와 같습니다.
(JEP 286) Local-variable type inference
var를 사용하여 생성할 변수의 타입을 추론할 수 있는 기능입니다.
개발자들에게 가장 크게 와닿을 기능인데요. 변수를 생성할 때, 앞쪽에 변수의 타입을 지정하고 뒤에서 생략하는 방식(Diamond operator)으로 java 1.7 버전에서 변경되었다면, jdk 10에서는 var를 통해 지역변수에 대해서는 Type을 명시해주지 않아도 됩니다.
//Java 1.6 or earlier jvm version
List<String> list = new ArrayList<String>();
//Java 1.7 or later jvm version
List<String> list = new ArrayList<>();
//Java 10
var list = new ArrayList<String>();
var stream = list.stream();
var는 keyword 가 아닌 reserved type으로 분류되는데요. 이는 여전히 var라는 이름으로 변수명이나 함수명을 만들 수 있음을 의미합니다.
(JEP 310) Application Class-Data Sharing
Class-Data Sharing(CDS)는 Java 5에서 소개되었었는데요. JVM 기동시의 성능을 향상하거나, 여러 대의 JVM이 하나의 물리 장비 또는 가상 장비에서 돌아가는 경우, 자원에 미치는 영향을 줄이기 위해 개발된 기능입니다.
CDS는 JVM에서 공통으로 사용하는 클래스들을 공유하는 저장소에 위치시키고 이를 공유해서 사용하는 방식으로 제공됩니다 (.jsa 파일)
CDS는 Java process 실행 시에 jvm option으로 CDS 사용 여부, 공유 저장소 이름 등을 전달하여 사용할 수 있습니다.
$ java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa -cp hello.jar
$ java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa -cp hello.jar HelloWorld
(JEP 314) Additional Unicode Language-Tag Extensions
java.util.Locale 클래스의 향상된 버전이며, Java 9에서 제공되는 BCP 47 Language tag에 몇 가지를 더 추가한 버전입니다.
- cu (currency type)
- fw (first day of week)
- rg (region override)
- tz (time zone)
그리고 위의 추가된 tag들을 지원하기 위한 API들이 추가되었습니다.
(JEP 322) Time-Based Release versioning
Java SE Platform과 JDK의 버전 명시에 대한 기준입니다. 기존에 versioning이 JEP 223에서 정의된 내용으로 적용되었지만, 시간이 지남에 따라, 버전 정보가 논리적이지 않게 적용되는 일이 발생하였습니다.
jdk 7의 Update 55와 Update 60 중, 어느 것이 더 많은 보안관련 수정을 포함할까요? 일반적으로 생각해보면, 55보다 60이 업데이트 번호가 크므로, 60이 더 많은 패치를 포함해야 합니다. 하지만, 실제로는 Update 55와 Update 60 모두 같은 보안관련 수정패치를 가리킵니다. 그렇다면 "JDK 7 Update 60", "1.7.0_60" 그리고 "JDK 7u60"의 차이점은 무엇일까요? 눈치채셨겠지만, 모두 같은 패치의 다른 이름일 뿐입니다.
이러한 문제를 해결하고, 새로운 버전 모델인 "Six-month release model"을 적용하기 위한 버전 표기법이 필요해졌습니다.
$FEATURE.$INTERIM.$UPDATE.$PATCH
- $FEATURE - Feature의 번호를 나타내는 값입니다. 기능의 내용에 상관없이 기능별로 번호가 하나씩 증가합니다.
- $INTERIM - 하위버전과 호환되는 Bug fixes와 enhancements의 경우에 증가하는 버전입니다.
- $UPDATE - 새로운 Feature에서 보안문제, 버그 등을 해결하는 경우에 증가하는 버전입니다.
- $PATCH - 중요한 문제를 해결하기 위해 비상으로 업데이트 될 경우에 증가하는 버전입니다.
(위 표기법은 JEP223의 표기법과 호환됩니다)
(JEP 319) Root Certificates
기본적인 Root Certification Authority(CA)세트를 제공합니다. OpenJDK 빌드와 Oracle JDK 빌드간의 차이를 줄이기 위해, Oracle Java SE의 루트 인증서를 오픈 소스로 만드는 목표를 가진 feature입니다. 이전까지는, cacerts 라고 불리는 JDK의 keystore에는 보안 프로토콜에 사용되는 루트 인증서 세트를 넣을 수 있는 곳이 존재했지만, 비어있었고, 사용자가 직접 문서화된 루트 인증서 세트를 채워야 했습니다.
(JEP 307) Parallel Full GC for G1
Full GC를 병렬로 만들어, G1의 worst-case latency를 개선하기 위한 feature입니다. 전체 Collection을 피하고자 jdk 9의 GC는 G1을 기본으로 하고 있지만, 빠르게 메모리를 회수할 수 없는 경우, 전체 GC가 하락하는 문제가 있었습니다.
G1은 잘 아시다시피 Mark-Sweep-Compact 알고리즘을 사용하는데요. 이전까지는 단일 쓰레드로 GC를 수행하였다면, jdk 10 부터는 병렬로 Mark-Sweep-Compact를 수행합니다. 이때, 쓰레드의 수는 기본적으로 Young and Mixed Collection의 쓰레드와 동일하고, 필요한 경우, -XX:ParallelGCThreads 옵션으로 조절 가능합니다. 하지만 이 옵션을 사용할 경우에는 Young and Mixed Collection의 쓰레드 수에도 영향을 미치기 때문에 주의할 필요가 있습니다.
New APIs
73개의 표준 클래스 라이브러리 API가 추가되었습니다. 대표적인 신규 API는 아래와 같습니다.
java.io.Reader
long transferTo(Writer);
reads all characters from this reader and writes the characters to the given writer in the order that they are read.
java.util.{Collection}
/**
*@Collection List, Map, Set
*/
static Collection copyOf(Collection);
These return an unmodifiable List, Map or Set containing the elements of the given Collection, in its iteration order.
java.util.{Optional}
/**
*@Optional Optional, OptionalDouble, OptionalInt, OptionalLong
*/
Throwable orElseThrow();
New method which essentially does the same as get(), i.e. if the Optional holds a value it is returned. Otherwise, a NoSuchElementException is thrown.
java.util.stream.Collectors
Collector toUnmodifiableList();
Collector toUnmodifiableSet();
Collector toUnmodifiableMap(Function, Function);
Collector toUnmodifiableMap(Function, Function, BinaryOperator);
These four new methods return Collectors that accumulate the input elements into the appropriate unmodifiable collection.