2023-09-16 작성

Java 8, 11, 17 버전별로 추가된 기능 알아보기

자바에서 가장 많이 사용되는 버전은 자바 8이다. 아직까지도 실무에서는 Java 8만 계속 사용하고 있지만, 2023년 9월 현재는 자바 21 버전까지 출시가 된 상태이다. 대표적인 Java LTS 버전은 자바 8, 11, 17가 있는데, 스프링부트 3 버전부터 자바 17 이상만 지원되면서 최근 자바 8에서 17 버전으로 전환되는 비율이 많아졌다.

 

각 버전별로 추가된 기능들과 예제를 살펴보면서 대략적인 특징을 살펴보자.

Java 8 에서 추가된 기능

  • 2014년 릴리즈
  • 오라클이 Sun Microsystems 인수 후 출시한 첫 번째 LTS 버전의 자바
  • 오라클사의 유료 버전인 Oracle JDK와 오픈소스 기반의 무료 버전인 Open JDK로 나뉨 (뜨거웠던 Java 유료 논쟁)
  • new Date and Time API (LocalDateTime 등)
  • Lambda, Stream API
  • Optional class
  • Interface Default Method

람다 (Lambda)

람다식(Lambda Expression)을 이용하여 간단한 식으로 표현할 수 있다. 메서드의 이름과 반환값(return)이 생략되므로 '익명 함수(anonymous function)'로 불린다. 코드가 간결해진다는 장점이 있지만, 람다식을 남용하면 오히려 코드를 이해하기 어려울 수 있다.

// 전통적인 방식
int max (int a, int b) {
    return a > b ? a : b;
}

// 람다식 방식
(a, b) -> a > b ? a : b;
// 전통적인 방식
for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

// 람다식 방식
IntStream.range(0, 10).forEach((int value) -> System.out.println(value));

스트림 (Stream API)

스트림(Steam)은 컬렉션의 저장 요소를 하나씩 순회하면서 처리할 수 있는 코드 패턴이다. 람다식을 지원한다는 점과 내부 반복자를 사용하기 때문에 병렬 처리가 쉽다는 특징이 있다. (스트림을 처음 봤을때 저게 무슨 소스인가 매우 난해한 기분이 들었다)

// 전통적인 방식
List<String> list = Arrays.asList("franz", "ferdinand", "fiel", "vom", "pferd");

// Stream으로 표현
list.stream()
    .filter(name -> name.startsWith("f"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);

interface default method

자바 8 이전의 인터페이스는 메서드 정의만 할 수 있었고 구현은 할 수 없었다. 8 버전부터 default method라는 개념이 생기면서 구현 내용도 인터페이스에 포함시킬 수 있게 되었다.

// 인터페이스 선언
public interface TestInterface {
    void doSomething();
    default void doSomethingDefault() {
        System.out.println("doing something default");
    }
}

// 인터페이스 구현
public class TestClass implements TestInterface {
    @Override
    public void doSomething() {
        System.out.println("doing something");
    }
}

TestClass testClass = new TestClass();
testClass.doSomething();          // 출력 결과 : doing something
testClass.doSomethingDefault();   // 출력 결과 : doing something default

Optional

Optional 클래스는 예상치 못한 NullPointerException이 발생될만한 상황에서 사용할 수 있다. null이 올 수 있는 값을 감싸는 Wrapper 클래스라서, NullPointerException이 발생하지 않도록 도와준다.

// 문자열로 Optional 객체 생성
Optional<String> optional = Optional.of("Hello world!");

// 문자열을 present로 체크
if (optional.isPresent()) {
	String value = optional.get();
	System.out.println(value);    // 출력 결과 : Hello world!
}
		
// 비어있는 Optional 객체 생성
Optional<String> emptyOptional = Optional.empty();

// optional이 빈 경우 디폴트값을 가져온다.
String value = emptyOptional.orElse("default value");
System.out.println(value);    // 출력 결과 : default value
		
// 예외 발생
emptyOptional.orElseThrow(() -> new RuntimeException("throw Exception"));

Java 11 에서 추가된 기능

  • 2018년 릴리즈
  • Oracle JDK와 Open JDK 통합되고 Oracle JDK가 구독형 유료 모델로 전환
  • 람다 지역변수 사용방법 변경
  • HTTP 클라이언트 표준화 기능
  • Third Party JDK로의 이전 필요
  • 앱실론 가비지 컬렉터 (Epsilon GC)

람다 지역변수 사용방법 변경

자바 10 버전에서 var 키워드가 추가되었다. var 키워드를 사용하는 경우 데이터 유형을 지정하지 않고 변수를 선언하고 정의할 수 있으며, 컴파일러는 할당된 데이터 유형에 따라 데이터 유형을 결정하게 된다.

자바 11부터는 람다식에서 var 키워드를 사용할 수 있게 되면서 파라미터 어노테이션도 적용할 수 있게 되었다.

// 자바 10에서 추가된 기능
(var s1, var s2) -> s1 + s2

// 자바 11에서 추가된 기능
(@NonNull var s1, @Nullable var s2) -> s1 + s2

HTTP Client

자바 11 이전에는 기본적인 URLConnection 구현 또는 Apache HttpClient 등의 타사 라이브러리에 의존해야 했지만, 자바 11 버전부터는 HTTP 표준 클라이언트를 구현하며, 동기 및 비동기 프로그래밍 모델인 HTTP/1.1 및 HTTP/2를 지원한다.

HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://test-api.com/posts"))
        .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Java 17 에서 추가된 기능

  • 2021년 릴리즈
  • 봉인 클래스(Seald Class) 정식 추가
  • 패턴 매칭 프리뷰 단계
  • Incubator (Foreign Function & Memory API)
  • 애플 M1 및 이후 프로세서 탑재 제품군에 대한 정식 지원
  • 의사난수 생성기를 통해 예측하기 어려운 난수를 생성하는 API 추가
  • 컨텐츠 기반의 역직렬화 필터링
  • Record Data Class 추가

봉인 클래스 (Seald Class)

봉인 클래스, 인터페이스는 상속하거나(extends), 구현(implements)할 클래스를 지정해 두고, 해당 클래스들만 상속 또는 구현을 허용하는 키워드이다. 개발자는 seald 키워드를 통해 어떤 클래스가 해당 클래스를 상속 또는 구현하는지를 쉽게 알 수 있고, 또 제한할 수 있다.

public sealed class Shape permits Circle, Square {
    // 공통 필드, 공통 메서드
}

public final class Circle extends Shape {
    // Circle 클래스의 필드, 메서드
}

public final class Square extends Shape {
    // Square 클래스의 필드, 메서드
}

Record Data Class

Record 키워드는 14 버전에서 프리뷰 기능으로 추가되었고, 16 버전에서 공식 기능이 되었다. Record 클래스는 불변 데이터를 객체 간에 전달하는 작업을 간단하게 만들어주며, record를 사용함으로써 불필요한 코드(boilerplate code)를 제거할 수 있고, 적은 코드로도 명확한 의도(data carrier)를 표현할 수 있다는 특징이 있다.

// Lombok 사용 예시
@EqualsAndHashCode
@ToString
@AllArgsConstructor
@Getter
public class Person {
    private final String name;
    private final String address;
}

// record class 예시
public record Person (String name, String address) { }

텍스트 블록 (Text Blocks)

텍스트 블록은 java 13, 14 버전에서 프리뷰로 추가되었고 15 버전에서 정식으로 발표되었다. 멀티 라인의 문자열을 에스케이프 시퀀스(\n) 없이 사용하므로 소스코드 작성이 편리하고, 코드 가독성을 높일 수 있다.

// 기존 소스
String html1 = "<html>\n" +
        "           <body>\n" +
        "               <p>Hello, world</p>\n" +
        "           </body>\n" +
        "       </html>\n";

// 텍스트 블록 적용
String html2 = """
        <html>
            <body>
                <p>Hello, world</p>
            </body>
        </html>
        """;

최근에 나온 LTS 버전인 Java 21국내에서는 아직 이르겠지만, 점차 Java 8이 수그러들면서 나중에는 Java 17과 21의 비교가 시작되지 않을까...하는 생각이 든다.

References