자바 8부터 21까지 버전별 주요 특징을 샘플 코드와 함께 쉽게 정리합니다. 각 버전의 핵심 기능, 변화 포인트, 실무 활용 예시를 초보자도 이해할 수 있게 설명합니다. 실습 위주의 예제로, 최신 자바의 흐름을 한 번에 파악할 수 있습니다.

들어가며

자바는 꾸준한 진화를 거듭해왔으며, 8버전 이후로는 거의 매년 새로운 기능과 개선이 추가되고 있습니다. 본 포스트에서는 자바 8부터 21까지의 주요 특징을 샘플 코드와 함께 간결하게 정리합니다. 실무에서 자주 쓰이는 기능 위주로, 각 버전의 대표적인 변화와 실제 코드를 통해 쉽게 이해할 수 있도록 구성했습니다.


1. Java 8 (2014) - 람다, 스트림, Optional

  • 람다(Lambda): 익명 함수로, 코드의 간결성과 함수형 프로그래밍 스타일을 도입. 기존의 익명 클래스보다 훨씬 짧고 명확하게 동작을 표현할 수 있습니다.
    • 예: list.forEach(e -> System.out.println(e));
    • 실무 활용: 콜렉션 처리, 이벤트 리스너, Comparator 등에서 코드가 획기적으로 짧아짐.
  • 스트림(Stream) API: 데이터의 집합을 함수형 스타일로 처리할 수 있는 강력한 API.
    • 예: list.stream().filter(x -> x > 10).collect(Collectors.toList());
    • 실무 활용: 대용량 데이터 필터링, 매핑, 집계 등에서 for문 대체. 병렬 처리도 지원(parallelStream).
  • Optional: NullPointerException 방지용 컨테이너. 값이 없을 수 있음을 명시적으로 표현.
    • 예: Optional.ofNullable(obj).ifPresent(System.out::println);
    • 실무 팁: 반환값이 null일 수 있는 메서드에 적극 활용, 단 Optional을 필드로 쓰는 것은 지양.
  • 기본형 함수형 인터페이스: Function, Predicate, Supplier, Consumer 등.
  • Date/Time API 개선: java.time 패키지 도입. Joda-Time 스타일의 불변 객체.
  • 기타: 디폴트 메서드, static 인터페이스 메서드, 반복문 개선 등.
// 람다와 스트림 예제
List<String> names = Arrays.asList("Tom", "Jerry", "Spike");
names.stream()
     .filter(n -> n.startsWith("T"))
     .forEach(System.out::println);

// Optional 예제
Optional<String> name = Optional.ofNullable(getName());
name.ifPresent(System.out::println);

2. Java 9 (2017) - 모듈 시스템, JShell

  • 모듈 시스템(Jigsaw): 대규모 프로젝트의 의존성 관리와 캡슐화 강화. module-info.java로 모듈 선언.
    • 실무 활용: 라이브러리, 플랫폼 분리. 하지만 대부분의 일반 프로젝트에서는 아직 적극 사용되지 않음.
  • JShell: 자바 최초의 REPL(Read-Eval-Print-Loop) 도구. 실시간으로 코드 조각을 테스트 가능.
    • 실무 활용: API 실험, 학습, 빠른 프로토타이핑에 유용.
  • 컬렉션 팩토리 메서드: List.of(), Set.of() 등 불변 컬렉션 생성이 간편해짐.
    • 예: List<String> list = List.of("a", "b", "c");
  • Stream API 개선: takeWhile, dropWhile, iterate 등 추가.
  • Private 인터페이스 메서드: 인터페이스의 코드 재사용성 증가.
// 컬렉션 팩토리 메서드
List<String> list = List.of("a", "b", "c");
Set<Integer> set = Set.of(1, 2, 3);

3. Java 10 (2018) - var 키워드

  • 지역 변수 타입 추론(var): 컴파일러가 타입을 추론해줌. 코드 가독성 및 생산성 향상.
    • 예: var list = new ArrayList<String>();
    • 실무 팁: 명확한 타입 추론이 가능한 곳에서만 사용 권장. 복잡한 타입일수록 가독성 저하 주의.
  • GC 개선: G1이 기본 GC로 채택.
  • Application Class-Data Sharing: 애플리케이션 시작 속도 개선.
var message = "Hello, Java 10!";
System.out.println(message);

4. Java 11 (2018) - String, HTTP Client

  • String 메서드 추가: isBlank, lines, strip, repeat 등 실무에서 자주 쓰이는 메서드들이 추가.
    • 예: " test ".strip();
  • 새로운 HTTP Client API: 비동기/동기 HTTP 요청을 표준화. 기존 HttpURLConnection의 대체.
    • 예: HttpClient.newHttpClient().send(request, ...)
    • 실무 활용: REST API 연동, 외부 서비스 통신에서 편리하게 사용.
  • 파일 읽기/쓰기 개선: Files.readString, writeString 등.
  • 런타임에서 JDK 모듈 제거: Java EE, CORBA 등 일부 모듈이 JDK에서 제거됨.
  • Lambda local variable type inference: 람다 파라미터에도 var 사용 가능.
// String 메서드
" java11 ".strip(); // 양쪽 공백 제거
"a:b:c".split(":");

// HTTP Client
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://example.com"))
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

5. Java 12~13 (2019) - Switch 개선, 텍스트 블록

  • Switch 표현식(프리뷰): 기존 switch문을 표현식으로 사용 가능, 화살표(->) 문법 도입.
    • 예: String result = switch (day) { ... };
    • 실무 팁: 복잡한 분기 처리에서 코드가 훨씬 간결해짐.
  • 텍스트 블록(프리뷰): 여러 줄 문자열을 쉽게 작성할 수 있는 문법(""" ... """).
    • 예: SQL, HTML, JSON 등 멀티라인 문자열 처리에 유용.
  • Compact Number Formatting: 숫자 포매팅에 compact 스타일 지원.
  • Shenandoah, ZGC: 새로운 가비지 컬렉터(프리뷰).
// Switch 표현식 (Java 12+)
int day = 3;
String dayType = switch (day) {
    case 1, 7 -> "Weekend";
    default -> "Weekday";
};

// 텍스트 블록 (Java 13+)
String html = """
    <html>
      <body>Hello, Java!</body>
    </html>
    """;

6. Java 14~15 (2020) - 레코드, 패턴 매칭(프리뷰)

  • 레코드(Record) 타입(프리뷰): 불변 데이터 클래스를 간단하게 정의할 수 있음.
    • 예: public record Point(int x, int y) {}
    • 실무 활용: DTO, VO 등 데이터 전달 객체에 최적.
  • instanceof 패턴 매칭(프리뷰): 타입 체크와 캐스팅을 한 번에.
    • 예: if (obj instanceof String s) { ... }
  • NullPointerException 메시지 개선: 어떤 객체에서 NPE가 발생했는지 메시지에 명확히 표시.
  • Text Blocks 정식 도입(Java 15): 여러 줄 문자열 문법이 정식 채택.
  • Sealed 클래스(프리뷰): 상속 계층을 제한해 설계의 명확성 강화.
// 레코드 (Java 14+)
public record Point(int x, int y) {}
Point p = new Point(1, 2);
System.out.println(p.x());

// instanceof 패턴 매칭 (Java 16)
if (obj instanceof String s) {
    System.out.println(s.toLowerCase());
}

7. Java 16~17 (2021) - Sealed 클래스, 새로운 API

  • Sealed 클래스(정식): 특정 클래스만 상속 가능하도록 제한.
    • 예: public sealed class Shape permits Circle, Rectangle {}
    • 실무 활용: 계층 구조 명확화, 유지보수성 향상.
  • Stream API 개선: toList(), mapMulti() 등 추가.
  • RandomGenerator API: 난수 생성기가 표준화되어 다양한 난수 알고리즘 지원.
  • Foreign Function & Memory API(프리뷰): 자바에서 네이티브 코드와 안전하게 상호작용.
  • Pattern Matching for switch(프리뷰): switch문에서 패턴 매칭 활용 가능.
// Sealed 클래스 (Java 17)
public sealed class Shape permits Circle, Rectangle {}
public final class Circle extends Shape {}
public final class Rectangle extends Shape {}

8. Java 18~19 (2022) - UTF-8 기본, Virtual Threads(프리뷰)

  • 기본 문자셋 UTF-8: 플랫폼과 무관하게 항상 UTF-8이 기본.
  • Virtual Thread(프리뷰): 경량 스레드로, 수십만 개의 동시 작업을 효율적으로 처리 가능.
    • 예: Thread.startVirtualThread(() -> ...);
    • 실무 활용: 대규모 동시성 처리, 서버 애플리케이션에 혁신적 변화.
  • Structured Concurrency(프리뷰): 동시 작업을 구조적으로 관리.
  • Simple Web Server: 간단한 정적 파일 서버 내장.
// Virtual Thread (Java 19)
Thread.startVirtualThread(() -> {
    System.out.println("Hello from virtual thread!");
});

9. Java 20~21 (2023) - Record Patterns, String Templates, 더 많은 패턴 매칭

  • Record Patterns: 레코드의 필드를 패턴 매칭으로 분해.
    • 예: if (obj instanceof Point(int x, int y)) { ... }
  • String Templates(프리뷰): 문자열 내에서 변수, 표현식 삽입이 간편해짐.
    • 예: STR."Hello \{name}!"
  • 패턴 매칭 강화: switch문, instanceof 등에서 다양한 패턴 매칭 지원.
  • Sequenced Collections: 순서가 있는 컬렉션 인터페이스 추가.
  • Scoped Values(프리뷰): 특정 스레드 범위 내에서만 값 유지.
  • Foreign Function & Memory API(정식): 네이티브 라이브러리와의 상호작용이 더 안전하고 쉬워짐.
// Record Pattern (Java 21)
record Point(int x, int y) {}

static void print(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println("x=" + x + ", y=" + y);
    }
}

// String Template (Java 21, 프리뷰)
String name = "World";
String message = STR."Hello \{name}!";
System.out.println(message);

10. 마치며: 버전별 변화, 어떻게 활용할까?

  • 각 버전의 변화는 생산성, 안전성, 코드 가독성, 성능에 직접적으로 영향을 줍니다.
  • 실무에서는 팀의 기술 스택, 라이브러리 호환성, 장기 유지보수성 등을 고려해 버전을 선택해야 합니다.
  • 새로운 문법이나 API는 실습을 통해 익히고, 공식 릴리즈 노트와 마이그레이션 가이드를 반드시 참고하세요.
  • 최신 버전의 기능을 적극적으로 도입하면, 코드 품질과 개발 속도 모두 향상됩니다.

참고 자료 및 레퍼런스


자바 8~21까지의 변화는 개발자에게 더 많은 생산성과 표현력을 제공합니다. 최신 기능을 적극적으로 익혀보세요!