반응형

Java 는 Version 별로 새로운 기능을 출시하는 등 큰 변경점이 있다. 버전 중에서도 LTS (Long Term Service) 버전들은 장기적으로 업데이트가 보장되므로 호환성이나 안정성 면에서 장점이 있다고 생각해 Java 8 과 11 의 각 변경점에 대해서 간단하게 정리를 해 보려고 한다.

 

Java 8

Java 8 은 2014 년 발표된 Java 버전으로 다음과 같은 주요 변경사항이 있었다.

  • Lambda 표현식
  • Stream API
  • java.time 패키지

람다 표현식 (Lambda Expression)

우선 람다 표현식이란, 익명 클래스의 한 개 메소드를 식으로 표현한 것이다. 여기서 익명 클래스란, 말 그대로 이름이 없는 클래스로 단 한 개의 객체만을 생성할 수 있는 일회용 클래스이다.

// 익명 클래스의 예
new Object() {
	int min(int x, int y) {
    	return x < y ? x : y;
    }
}
// 람다 표현식의 예
(x, y) -> x < y ? x : y;

이러한 람다 표현식은 매개변수로 전달될 수 있으며, 메소드의 결과값으로 반환될 수도 있다. 따라서 람다 표현식을 사용할 경우 기존의 불필요한 코드를 줄이고 작성된 코드의 가독성을 높일 수 있다. Java 8 부터는 이러한 람다 표현식을 사용해 자바에서도 함수형 프로그래밍이 가능하게 되었다.

스트림 API (Stream API)

자바에서는 여러 데이터를 저장하기 위해 배열 / 컬렉션을 사용한다. 그리고 이렇게 저장된 데이터에 접근하기 위한 방법으로 반복문이나 Iterator 를 사용해 매번 코드를 작성해야 했다.

하지만 이렇게 작성된 코드는 길이가 길고 가독성도 떨어지며, 코드의 재사용이 거의 불가능하다. 또한, 정형화된 처리 패턴을 가지지 못하기 때문에 데이터마다 다른 방법으로 접근해야 했다.

이러한 문제를 극복하기 위해 도입된 방법이 바로 스트림 API 이다. 스트림 API 는 데이터를 추상화해서 다루므로, 다양한 형태로 저장된 데이터를 위한 공통된 방법을 제공한다. 따라서 스트림 API 를 사용하면 배열이나 컬렉션 뿐 아니라, 파일에 저장된 데이터도 모두 같은 방법으로 다룰 수 있다.

 

다음은 스트림 API 를 사용한 예제이다.

// 정수형 배열에서의 스트림 생성
int [] arr1 = new int[]{1, 5, 11, 13, 20, 52};
Stream stream1 = Arrays.stream(arr1);
stream1.map(i -> i * 2);
stream1.filter(i -> i % 2 == 0); // 재사용이 불가능하기 때문에 에러 발생

// 정수형 배열에서 스트림 생성
int [] arr2 = new int[]{1, 5, 11, 13, 20, 52};
Stream stream2;
stream2 = Arrays.stream(arr2)
				.filter(i -> i % 2 != 0)	// {1, 5, 11, 13}
                .map(i -> i * 2);			// {2, 10, 22, 26}

java.time 패키지

java.time 패키지는 기존에 사용하던 Date 클래스나 Calendar 클래스의 문제를 해결하기 위해 새롭게 등장한 날짜/시간 API 패키지이다.

 

Java 11

Java 11 은 2018 년에 발표된 Java 버전으로 Java 8 이후 최초로 공개된 Java 의 LTS 버전이다. Oracle 은 Java 8 에 대한 지원을 2019 년에 중단했고, Java 11 은 많은 변화가 있었다.

 

Local-Variable Syntax for Lambda Parameters

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

list.stream()
	.map((var s) -> s.toLowerCase())
    .collect(Collectors.toList());

물론 기존의 람다 표현식에서도 타입을 생략하면, 컴파일러가 컴파일 시 s 의 타입을 String 으로 추론한다. 그렇다면, jdk 8 의 추론 방법이 더 간단한데 왜 이런 feature 가 추가되었을까?

Align the syntax of a formal parameter declaration in an implicitly typed lambda expression with the syntax of a local variable declaration.

JEP 323의 Goals 를 보면, 위와 같이 명시되어있는데 jdk 10 에서 명시적으로 선언되던 구문을 var 로 선언할 수 있게 되었고, 이런 특징을 람다 표현식에도 적용해, 암시적으로 선언되던 형태를 var 로 선언해 표현식을 통일할 수 있게 되었다.

또한, 이렇게 명시적으로 선언하면 람다표현식에서 어노테이션을 사용하는 경우 아래와 같이 조금 더 간단하게 코드를 작성할 수 있다.

list.stream()
	.map((@NotNull var s) -> s.toLowerCase())
    .collect(Collectors.toList());

HTTP Client (Standard)

jdk 9 에서 추가되고 jdk 10 에서 업데이트된 java.incubator.http 패키지가 인큐베이터에서 나와 java.net.http 패키지로 표준화되었다. 이 패키지가 개발된 이유는 아래와 같다.

  • 베이스가 되는 URLConnection API 가 현재는 거의 사용되지 않는 프로토콜을 염두에 두고 설계되었다.
  • HTTP/1.1 보다 너무 추상적이다.
  • 문서화가 잘 되어있지 않아 사용이 어렵다.
  • Blocking 형태로만 동작한다.
  • 유지보수의 어려움이 있다.

java.net.http 로 옮겨진 패키지의 기능은 아래와 같다.

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

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

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

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

알다시피, JVM 으로 구동되는 어플리케이션의 경우는 GC 가 동작할 때 어플리케이션이 멈추는 현상은 성능에서 큰 영향을 끼쳐 왔다. 이러한 정지시간을 줄이거나 없앰으로써 어플리케이션의 성능 향상에 기여할 수 있다.

ZGC 의 주요한 원리는 Load Barrier 와 Colored Object Pointer 를 동시에 사용하는 것이다. 이를 통해 Java 의 어플리케이션 스레드가 동작하는 중간에, ZGC 가 객체 재배치 같은 작업을 수행할 수 있게 해준다.

 

이 외에도, 다양한 성능적 향상이 java 8 버전에 비해 제공된다고 한다.

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

[Java] Annotation 이란?  (0) 2021.11.03
[Java] 서블릿 (Servlet) 과 JSP (Java Server Page)  (0) 2021.09.30
JPA 란?  (0) 2021.06.18

+ Recent posts