inblog logo
|
LifeLog, DevLog
    Java

    Java 8 부터의 버전별 차이 정리

    KYJTHEYJ's avatar
    KYJTHEYJ
    Nov 10, 2025
    Java 8 부터의 버전별 차이 정리
    Contents
    Java 8Java 9~11Java 12~16Java 17Java 21Java 25

    Java 8

    • Stream, Lambda, Optional
      • Stream
        • for, if 사고에서 전환 → 데이터를 흐름으로 판단한다
      • Lambda
        • 익명클래스 → 람다
      • Optional
        • NULL 체크를 위한 Optional 객체
     

    Java 9~11

    • 타입 추론, HttpClient의 표준화
      • 10 버전
        • var 타입 추론 기능 → 명시적 타입 중복 선언 제거
        • var list = List.of(1,2,3,4); // var -> 자동으로 List<Integer> 추론
      • 11 버전
        • HttpClient의 표준화 (HttpURLConnection 연결 코드 → 외부 API 통신도 Stream 처럼)
        • HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create("http://url~")).GET().Build(); HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
     

    Java 12~16

    • Switch 표현 개선 , “”” 텍스트 블록, Record 클래스 (17에서 안정화)
      • Switch 표현 개선 및 결과를 만드는 표현식으로 변경 → 1급 객체스럽게 변경됨 (statement에서 expression으로 바뀐 것)
      • String result = switch (value) { case A, B -> "Pass"; case C, D -> "Re-Learn"; default -> "Fail"; };
      • “”” 텍스트 블록 → 문자열 표현의 개선
      • String query = """ SELECT * FROM food f where f.price >= 10000 """;
      • Record 클래스 → 불변 DTO 서술, 편리성 제공
      • public record User(String id, String pwd) {}
     

    Java 17

    • Sealed Class, 타입 매칭 검사의 패턴 매칭
      • Sealed Class로 상속, 구현 클래스를 선언 및 지정하여 해당 클래스만 상속, 구현이 되도록 제한 하는 기능
        • sealed → 상속 제한의 부모 클래스
        • permits → 어떤 클래스만 상속 받을지 명시
        • final → 더 이상 상속 불가하도록 선언
        • non-selad → 다시 자유로운 상속 선언 (sealed class 조상이 있어야 사용가능한 키워드)
    public sealed class Parent permits Child, Child2 { // sealed class 로 상속 클래스 선언, Child만 상속되도록 permits 키워드 사용 public String familyName = "김"; public void introduce() { System.out.println("김씨 가문"); } } public non-sealed class Child extends Parent { // 상속 받은 Child 클래스 -> 아무나 자유롭게 상속 가능 } public final class Child2 extends Parent { // 상속 받은 Child2 클래스 -> 더는 상속 불가 선언 }
     
    • 타입 매칭 검사의 패턴 매칭
    //기존 if (object instanceof String) { String str = (String) object; } //17 if (object instanceof String str) { System.out.println(str.length()); }
     

    Java 21

    • 동시성을 위한 가상 쓰레드, Sequenced Collections
      • Virtual Thread의 도입
        • 기존 쓰레드는 OS의 쓰레드와 1:1 매핑으로 메모리 차지가 매우 크고, 1만개 이상 적용이 힘들었음
        • JVM이 스케줄링하는 더 가볍고, 대량 실행이 가능하며, I/O와 대기에 관해 설계 경량화를 위해 개발됨
        // 기존 Runnable1 runnable1 = new Runnable1(); Thread t1 = new Thread(runnable1); long start = System.currentTimeMillis(); t1.start(); try { t1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("합계 : " + runnable1.getSum()); long end = System.currentTimeMillis(); System.out.println("실행시간 : " + (end - start)); // 가상쓰레드로 전환시 Runnable1 runnable1 = new Runnable1(); long start = System.currentTimeMillis(); // 가상 쓰레드 생성 + 즉시 시작 Thread thread1 = Thread.ofVirtual().start(runnable1); try { thread1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } long end = System.currentTimeMillis(); System.out.println(end - start);
     
    • Sequenced Collection
      • 컬렉션에서 앞과 뒤의 개념을 공통으로 다루도록 통합한 것 → 순서를 1급 객체의 개념으로 다룸 → 순서의 보장
        • SequencedCollection, SequencedSet, SequencedMap 인터페이스의 생성
          • 기존의 List, LinkedHashSet, LinkedHashMap이 이 인터페이스들을 구현하도록 바뀜
            • 그래서 Linked 되지 않은 클래스들은 addFirst, addLast, getFirst, getLast() 의 메서드를 사용하지 못했는데 이제 가능
        public class Cart { private final ArrayList<Product> cart; public Cart() { cart = new ArrayList<>(); } public Cart(ArrayList<Product> cart) { this.cart = cart; } public void addProduct(Product product) { //cart.add(product); -> 기존엔 add(index 입력, Product) 로 밖에 Linked가 아닌 이상 못했음 cart.addLast(product); // 앞과 뒤의 개념을 공통으로 다루도록 되어 맨 뒤에 추가 가능 } }
     

    Java 25

    • 동시성 보장을 위한 Scoped Value
      • 각 쓰레드의 독립적인 저장 공간을 제공하는 ThreadLocal은 구조적 문제가 있었음
      • ThreadPool로 여러 쓰레드를 재사용하는 환경에서는 값이 남아 다른 요청에 섞이는 문제와 메모리 누수가 있었음
      • 어떤 코드의 범위에선 이 값이 유효한지 알수가 없었음
      • 21에 추가된 가상 쓰레드의 개념과 섞일 수가 없음 (가상 쓰레드는 JVM이 스케줄링하므로 값이 더 꼬인다는 문제가 잔존)
      • public class Example { private static final ThreadLocal<Integer> counter = ThreadLocal.withInitial(() -> 0); public static void main(String[] args) { Runnable task = () -> { for (int i = 0; i < 3; i++) { counter.set(counter.get() + 1); // 값을 지정하는 부분 System.out.println(Thread.currentThread().getName() + " : " + counter.get()); } }; new Thread(task, "A").start(); new Thread(task, "B").start(); } } // 각각 A : 1..2..3 B: 1..2..3 출력 // 여기서는 각각 쓰레드가 자기만의 counter 복사분을 지님 // 수동으로 get(), set(), remove() 해주어야 관리됨 import java.util.concurrent.Executors; import java.util.stream.IntStream; import java.lang.ScopedValue; public class ScopedExample { static final ScopedValue<Integer> COUNTER = ScopedValue.newInstance(); public static void main(String[] args) throws Exception { try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { // Executors를 통한 비동기 처리 + 가상쓰레드 실행 + var를 통한 추론 IntStream.range(0, 2).forEach(i -> executor.submit(() -> { ScopedValue.where(COUNTER, 0).run(() -> { runTask("Thread-" + i); }); // 값을 지정하는 부분 }) ); } } static void runTask(String name) { for (int i = 0; i < 3; i++) { int next = COUNTER.get() + 1; ScopedValue.where(COUNTER, next).run(() -> { System.out.println(name + " : " + COUNTER.get()); }); } } } // 가상 쓰레드 사용 + 스코프로 값의 유효 범위를 지정 // 스코프가 끝나면 자동으로 값이 해제됨
     
    Share article
    Contents
    Java 8Java 9~11Java 12~16Java 17Java 21Java 25

    LifeLog, DevLog - https://github.com/KYJTHEYJ

    RSS·Powered by Inblog