Java RoadMap 그리고 JDK9 ~ 11 변경사항

Java RoadMap 그리고 JDK9 ~ 11 변경사항

Oracle이 Java를 유료화 선언한 후 변경된 Java RoadMap은 다음과 같다. 현재 프로그램 언어 시장은 지각 변동하고 있으며 이에 Java진영도 JDK9부터 빠른 업데이트 주기를 가지고 제품을 출시하고 있다.

Oracle Java Support RoadMap

출시공식 업데이트 종료Premire SupportExtended Support
JDK82014.032019.012022.032030.12
JDK92017.092018.032018.03Not Available
JDK102018.032018.092018.09Not Available
JDK112018.092019.032023.092026.09
JDK122019.032019.092019.09Not Available
JDK132019.092020.032020.03Not Available
JDK142020.032020.092020.09Not Available
https://www.oracle.com/java/technologies/java-se-support-roadmap.html
Premire Support

제품 출시 후 5년간 제공되는 가장 다양한 Java update 지원 유상 서비스

Extended Support

Premire Support 종료 후 3년간 제공되는 추가 기술지원 서비스

JDK8은 현재 가장 많이 사용되고 있는 안정화된 Java 버전으로 공식 업데이트 기간은 종료되었지만 많이 사용되고 있는 만큼 추가 지원기간이 꽤 길게 잡혀있다.

JDK9부터 6개월마다 Major 버전 업데이트를 하도록 변경되었다. JDK9, 10은 LTS 버전이 나오지 않아 지원기간이 짧다.

JDK11부터 LTS(Long Term Support)가 생겨났으며 Premire + Extended Support로 최대 8년간 보안 업데이트와 버그 수정 지원을 받을 수 있게 되었다.

총 149개의 JDK Enhancement Proposals이 JDK14까지 반영되었다.

왜 6개월마다 Major 업데이트하는 방식으로 바뀌었나?

Java는 굉장히 보수적인 개발 언어로 하나의 버전이 정말 오랫동안 사용되고 있다. 다음 버전이 나오는 데까지도 시간이 오래 걸린다. 하지만 근래 등장하는 언어들은 업데이트 주기가 짧고 최신 기술을 빠르게 받아들이는 쪽으로 언어가 발전하고 있다. 이에 비해 Java는 이러한 변화의 속도를 따라가지 못하고 있으며 빠른 시간 내에 경쟁에서 밀려 도태될 것이란 전망도 나오고 있다.

Java 진영도 이에 위기감을 느낀 것인지 새로운 기능 출시 및 개발자들의 피드백을 빠르게 반영하기 위해 6개월마다 Major 업데이트를 실시 하도록 변경되었다.

그래프를 보면 JDK9에서 91개의 개선안이 수용되어 버전업이 되었고 그 뒤로는 6개월마다 10개 정도의 개선안이 빠르게 적용되면서 기존보다 빠른 기능 업데이트를 실시하고 있는것을 볼 수 있다.

JDK9 주요 변경사항

전반적으로 Java8에서 아쉬웠다고 생각되었던 부분들이 대거 보강되었다.

https://www.oracle.com/java/technologies/javase/9-relnotes.html

Java Platform Module System(Jigsaw) 추가

유연한 런타임 이미지를 만들기 위해 Java 플랫폼을 모듈화 하여 필요한 모듈만으로 경량화된 이미지를 만들 수 있게 되었다. 기존에는 JRE 일부분만 배포가 불가능했지만 Jigsaw를 통하여 원하는 모듈만 모아 런타임 환경 이미지를 만들 수 있게 되었다. (소형 디바이스, 마이크로 서비스, 시작 시간 단축 등을 염두한 것으로 보인다.)

Process API Updates

운영체제의 프로세스 제어 및 관리를 위한 API의 기능이 향상되었다.

JShell 추가

javascript(node), python 같은 인터프리터 언어의 shell 환경처럼 바로 코드를 작성하고 결과를 확인할 수 있는 REPL(Read-Eval-Print-Loop) 도구를 제공한다. 번거롭게 java파일을 만들고 컴파일해서 결과를 볼 필요 없이 코드를 작성하고 바로 실행하여 결과를 확인할 수 있다.

Compact String

자바의 기본 char형은 UTF-16기반의 2byte를 차지하는데 개선된 String은 문자열에 따라 Latin-1(1byte)와 UTF-16(2byte)으로 나누어졌다. 만일 영어만 있는 문자열의 경우 1byte의 영역을 차지해 기존보다 메모리 공간을 절약할 수 있게 되었다.

HTML5 Javadoc / Javadoc Search

이전 버전까진 HTML 4.01 형식으로 JavaDoc을 생성하였으나 이제 HTML5 방식의 마크업으로 Javadoc을 생성할 수 있다. Javadoc 문서에서 프로그램 요소, tag가 지정된 단어나 문구를 검색하는 데 사용할 수 있는 검색 상자를 사이트상에서 사용할 수 있다. 검색 기능은 로컬에 구현되며 서버 사이드의 연산에 의존하지 않는다.

UTF-8 Property Files

properties file에 대한 기본적인 파일 인코딩이 기존 ISO-8859-1에서 UTF-8 로 변경되었다.

Multi-Release JAR Files

JAR 파일 형식을 확장하여 여러 버전의 클래스 파일을 하나의 JAR 안에 공존시킬 수 있다. 즉 동일한 클래스를 Java버전 별로 동작할 수 있게 구성하여 jar 안에 넣을 수 있다.

More Concurrency Updates (reactive stream)

프로그램의 동시성 및 병렬 처리 지원을 위한 라이브러리의 지원이 늘어났다. 개선된 CompletableFuture과 Reactive stream이 도입되었다.

Unicode 8.0

Unicode 6.1을 지원했던 java8에 비해 10,555자, 29개의 스크립트 및 42개 블록의 유니코드 8.0을 지원한다.

Convenience Factory Methods for Collections

불변 Collection을 만들 수 있는 편리한 메서드가 생겼다.

// java8
Set<String> set = Collections.unmodifiableSet(Stream.of("a", "b", "c").collect(toSet()));

// 이후 java
Set<String> set = Set.of("a", "b", "c");
List.of(a, b, c);
Set.of(d, e, f, g);
Map.of()
Map.of(k1, v1)
Map.ofEntries(
    entry(k1, v1),
    entry(k2, v2),
    entry(k3, v3),
    // ...
    entry(kn, vn));

SHA-3 Hash Algorithms

SHA-1, SHA-2 표준 해시 함수를 대체하는 진보된 암호화 해시 함수를 구현하여 제공한다.

Deprecate the Applet API

더 이상 브라우저에서 사용하지 않는 applet api에 대한 지원이 종료되었다.

Implement Selected ECMAScript 6 Features in Nashorn

Jvm의 공식 javascript 엔진인 Nashorn이 ECMAScript 6 버전의 많은 새로운 기능 중 일부를 구현하여 제공한다.

Private Interface Method

 interface 에 private method / private static method라는 새로운 기능을 제공한다.

public interface IMyInterface {
 
    private void method1(String arg) {
    // do something
    }
 
    private static void method2(Integer arg) {
    // do something
    }
}

try-with-resource 향상

java7에서 등장했던 try-with-resources의 불편사항이 개선되었다.

void tryWithResourcesByJava7() throws IOException {
BufferedReader reader1 = new BufferedReader(new FileReader("test.txt"));
    try (BufferedReader reader2 = reader1) {
        // do something
    }
}
// final or effectively final이 적용되어 reader 참조를 사용할 수 있음
void tryWithResourcesByJava9() throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
try (reader) {
        // do something
    }
}

Improve Diamond Operator

익명 클래스에 Diamond Operator를 사용할 수 있게 되었다.

// java7,8
MyHandler<Integer> intHandler = new MyHandler<>(10) { // Anonymous Class };  //오류

// java9
MyHandler<Integer> intHandler = new MyHandler<>(10) {
    @Override
    public void handle() {
        // handling code...
    }
};

Stream Improvements

Java 9 Stream 은 iterate(), takeWhile()/dropWhile(), ofNullable() 과 같은 새로운 추가 메서드를 제공하여 비동기 프로그래밍에 대한 몇 가지 유용한 개선 사항을 제공한다.

Optional class Stream

Optional class에 or(), ifPresentOrElse(), stream() 메서드가 추가되어 활용도가 높아졌다.

JDK10 주요 변경사항

https://www.oracle.com/java/technologies/javase/10-relnotes.html

Local-variable type inference

var를 사용하여 생성할 변수의 타입을 추론할 수 있는 기능이 추가되었다. 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();

Application Class-Data Sharing

Class-Data Sharing(CDS)는 JVM 기동시의 성능을 향상하거나, 여러 대의 JVM이 하나의 물리 장비 또는 가상 장비에서 돌아가는 경우, 자원에 미치는 영향을 줄이기 위해 개발된 기능이다. CDS는 JVM에서 공통으로 사용하는 클래스들을 공유하는 저장소에 위치시키고 이를 공유해서 사용하는 방식으로 제공된다 (.jsa 파일)

Additional Unicode Language-Tag Extensions

java.util.Locale 클래스의 향상된 버전으로 Java9에서 제공되는 BCP 47 Language tag에 몇 가지를 더 추가한 버전이다.

  • cu (currency type)
  • fw (first day of week)
  • rg (region override)
  • tz (time zone)

Time-Based Release versioning

Java SE Platform과 JDK의 버전 명시에 대한 기준이 생겼다. 새로운 버전 모델인 “Six-month release model“을 적용하기 위한 버전 표기법으로 등장하였다.

$FEATURE.$INTERIM.$UPDATE.$PATCH

$FEATURE - 주버전. Feature의 번호를 나타내는 값입니다. 기능의 내용에 상관없이 기능별로 번호가 하나씩 증가합니다.
$INTERIM - 개선 버전. 하위버전과 호환되는 Bug fixes와 enhancements의 경우에 증가하는 버전입니다.
$UPDATE - 업데이트 버전. 새로운 Feature에서 보안문제, 버그 등을 해결하는 경우에 증가하는 버전입니다.
$PATCH - 중요한 문제를 해결하기 위해 비상으로 업데이트 될 경우에 증가하는 버전입니다.

Root Certificates

기본적인 Root Certification Authority(CA)세트를 제공한다. OpenJDK 빌드와 Oracle JDK 빌드간의 차이를 줄이기 위해, Oracle Java SE의 루트 인증서를 오픈 소스로 만드는 목표를 가진 feature다. 이전까지는, cacerts 라고 불리는 JDK의 keystore에는 보안 프로토콜에 사용되는 루트 인증서 세트를 넣을 수 있는 곳이 존재했지만, 비어있었고 사용자가 직접 문서화된 루트 인증서 세트를 채워야 했다.

Parallel Full GC for G1

Full GC를 병렬로 만들어, G1의 worst-case latency를 개선하기 위한 feature다. 이전까지는 단일 스레드로 GC를 수행하였다면, jdk 10부터는 병렬로 Mark-Sweep-Compact를 수행한다.

New APIs

73개의 표준 클래스 라이브러리 API가 추가되었다. 대표적인 신규 API는 아래와 같다.

java.io.Reader

long transferTo(Writer);

모든 문자를 읽고 주어진 순서대로 지정된 writer에 문자를 쓴다.

Optional.orElseThrow() Method

get() 메서드의 대안으로써 본질적으로 동일한 새로운 메서드. Optional이 값을 보유하면 반환된다. 그렇지 않으면 NoSuchElementException이 발생한다.

APIs for Creating Unmodifiable Collections

Unmodifiable Collections(수정할 수 없는 컬렉션)을 쉽게 만들 수 있는 몇 가지 새로운 API가 추가되었다.

아래 메서드는 기존 인스턴스에서 새 Unmodifiable Collection 인스턴스를 만든다.

  • List.copyOf
  • Set.copyOf
  • Map.copyOf

Stream 패키지의 Collectors 클래스에 다음과 같은 메서드가 추가되었다.
이것에 의해 Stream의 요소를 Unmodifiable Collections에 수집할 수 있습니다.

  • Collector toUnmodifiableList();
  • Collector toUnmodifiableSet();
  • Collector toUnmodifiableMap(Function, Function);
  • Collector toUnmodifiableMap(Function, Function, BinaryOperator);

JDK11 주요 변경사항

https://www.oracle.com/java/technologies/javase/11-relnotes.html

Local-Variable Syntax for Lambda Parameters

jdk 10 버전에서 지역변수로써 사용되어 타입을 추론할 수 있는 var가 새로운 feature로 추가되었었는데, jdk 11 버전에서는 var를 람다 표현식에 쓰는 경우 전달되는 parameter들의 타입을 추론할 수 있는 feature가 추가되었다.

HTTP Client (Standard)

jdk 9에서 추가되고 jdk 10에서 업데이트된 java.incubator.http 패키지가 인큐베이터에서 나와 java.net.http 패키지로 표준화되었다. 구버전의 HttpUrlConnection을 대체한다.

  • Non-Blocking request and response 지원 (with CompletableFuture)
  • Backpressure 지원(java.util.concurrent.Flow 패키지를 통해 RX Flow를 구현체에 적용)
  • HTTP/2 지원
  • Factory method 형태로 지원
  • websocket 지원

ZGC: A Scalable Low-Latency Garbage Collector (Experimental)

jdk 11에서 새로 등장한 가비지 컬렉터로 ZGC라고도 불리는 이 가비지 컬렉터는 아래의 몇 가지 목표를 가지고 개발되었다.

  • GC 일시 중지 시간은 10ms를 초과하지 않는다.
  • 작은 크기(수백 메가) ~ 매우 큰 크기(수 테라) 범위의 힙을 처리한다.
  • G1에 비해 애플리케이션 처리량이 15%이상 감소하지 않는다.
  • 향후 GC 최적화를 위한 기반 마련.
  • 처음에는 Linux / x64을 지원 (향후 추가 플랫폼 지원 가능).

Flight Recorder

Oracle Java의 상용 addon이었던 JFR(Java Flight Recorder)를 오픈소스로 개발하였다. JFR은 실행 중인 Java 애플리케이션의 진단 및 프로파일링 데이터를 수집하는 도구다. 주로 실행 중인 Thread, GC Cycles, Locks, Sockets, 메모리 사용량 등에 대한 데이터를 수집한다.

Launch Single-File Source-Code Programs

Single file 프로그램의 Main 메서드 실행 시 javac를 하지 않고도 바로 실행할 수 있도록 편의성이 향상되었다.

# Before Java 11
$ javac Hello.java
$ java Hello

# Now Java 11
$ java Hello.java

“Shebang” files

스크립트 언어를 작성하듯이 첫줄에 shebang을 선언하고 java프로그램을 작성하면 아래와 같이 실행가능 하다.

$ vi run.sh 
#!/opt/java/openjdk/bin/java --source 11
public class SheBang {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}
$ ./run.sh

Deprecate the Nashorn javascript Engine

빠른 변화에 맞추어 대응하기가 어렵다고 판단되어 Javascript 엔진은 Deprecate 되었다.

Java8에서 Java11로의 전환

Java 8 이후로 새 기능이 추가되고 기능이 향상되었다. 이러한 새 기능과 향상된 기능은 시작, 성능, 메모리 사용을 개선하며 컨테이너(Docker 포함)와의 보다 원활한 통합을 제공한다. 그리고 개발자 생산성을 개선할 수 있도록 새 API가 추가되고 기존 API가 수정되었다.

아쉽게도 전환을 위한 완전한 solution은 제공되지 않는다. 제거된 api, 사용되지 않는 패키지, 내부 api사용, 클래스 로더 변경, 가비지 수집 등의 차이점에 대한 테스트가 필요하다. 사실 JDK에서 제거된 JavaEE 또는 CORBA모듈에 의존하는 경우를 제외하고는 큰 문제없이 JDK11에서 실행될 수 있다.

Java 11에는 잠재적인 이슈를 해결하는 데 유용하게 사용할 수 있는 두 가지 도구인 jdeprscan 및 jdeps가 포함되어 있다. 

jdeprscan은 더 이상 사용되지 않거나 제거된 API 사용을 찾는다. 

jdeps는 Java 클래스 종속성 분석기다. --jdk-internals 옵션과 함께 사용할 경우 jdeps는 어떤 클래스가 어떤 내부 API에 종속되는지 알려준다. Java 11에서 내부 API를 계속 사용해도 되지만, 사용 방법을 바꾸는 것을 최우선으로 해야 한다.

Gradle과 Maven에 모두 사용할 수 있는 jdeps 및 jdeprscan플러그 인이 있다. 빌드 스크립트에 이러한 도구를 추가해 놓는 것이 좋다.

도구Gradle 플러그 인Maven 플러그 인
jdepsjdeps-gradle-pluginApache Maven JDeps 플러그 인
jdeprscanjdeprscan-gradle-pluginApache Maven JDeprScan 플러그 인

Transition from java8 to 11

https://docs.microsoft.com/ko-kr/azure/developer/java/fundamentals/transition-from-java-8-to-java-11

공유