Spring Framework 6.0, Spring Boot 3.0 에서 Java 17 버전을 선택하여 9 버전 이후부터 업데이트 된 내용을 확인하고자 한다.
[Preparing for Spring Boot 3.0](https://spring.io/blog/2022/05/24/preparing-for-spring-boot-3-0)

Java 11(LTS) 까지의 업데이트

  • Java 9
    • Jigsaw module system 참고:Baeldung
      • 라이브러리와 규모가 큰 시스템을 모듈화하고 강력한 접근 제어를 통해 느슨한 결합, 모듈 간 결합 방지, 보안성 향상 등에 이점을 갖는다
      • JPMS(Java Platform Module System)의 일환으로 JRE를 작은 단위 모듈로 쪼개고 사용하는 모듈만 패키징하여 배포 가능(module-info.java)
    • JShell(The Java Shell (Read-Eval-Print Loop)) Tool
      • script 형태로 Main Method 없이 즉석에서 실행 가능한 도구
    • jlink(The Java Linker)
      • 최근에는 JDK만 제공하고 JRE는 제공하고 있지 않기 떄문에 필요시 jlink 기능을 사용하여 추출 가능
    • Immutable Set(of)
      Set<String> keySet = Set.of("key1", "key2", "key3")
      
    • Optional.stream()
      List<String> filteredList = listOfOptionals.stream()
                  .flatMap(Optional::stream)
                  .collect(Collectors.toList());
      
    • Interface private method 도입
      @FunctionalInterface
      public interface PrivateMethodInterface {
          private static String staticPrivate() {
              return "Static Private";
          }
          
          private String instancePrivate() {
              return "Instance Private";
          }
          
          void printPrivateMethod();
          
          default void check() {
              String result = staticPrivate();
              PrivateMethodInterface privateMethodInterface = () -> {
                  System.out.println(this.instancePrivate());
              };
          
              privateMethodInterface.printPrivateMethod();
              result = privateMethodInterface.instancePrivate();
          }
      }
      
    • New HTTP Client
      • java.net.http 패키지하에 있는 신규 API로 HTTP/2 프로토콜, 웹소켓을 지원한다 ```java HttpRequest request = HttpRequest.newBuilder() .uri(new URI(“http://localhost:8080/members”)) .GET() .build();

      HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); ```

  • Java 10
    • Optional.orElseThrow
    • var 변수 선언 가능(타입 추론) 참고:Java 10 LocalVariable
      • 주의사항
        var variable1; // compile error without initializer
        var variable2 = null; // compile error is null
        public var variable3 = "Hello Java10"; // compile error non-local variable
        var lambda = (String s) -> s.length > 10; // lambda expression needs an explicit target-type //Predicate<String> filter = s -> s.length() > 10;
        var arr = {1, 2, 3}; // compile error, array initializer needs an explicit target-type
        
      • 사용 방법
        int[] arr = {1, 2, 3};
        for (var n : arr) {
            System.out.println(n);
        }
        var map = new HashMap<Integer, String>();
        
    • 불변 컬렉션 생성 메소드 추가(copyOf, toUnmodifiableSet, …)
    • Parallel Full GC for G1
      • G1GC에서 Full GC 발생 시 병렬 처리하여 성능 향상
  • Java 11
    • HTTP Client (http://openjdk.org/jeps/321)
      • non-blocking backpressure를 이용한 비동기 스트림 처리 지원 API 추가
      • HTTP2 를 구현하는 신규 클라이언트 API 제공, 기존 HttpURLConnection API 대체
    • ZGC
      • Z GarbageCollector로 stop-the-world 성능 저하 개선을 위한 목적으로 개발
        • 처리시간이 10ms 를 초과하지 않아 짧은 지연시간 보장
    • Lambda 내에서도 var 변수 사용 가능
      Stream.of(1, 2, 3, 4)
          .map((var i) -> i * 2);
          .collect(Collectors.toList());
      
      • var 를 붙이는 이유는, var 앞에 @NonNull과 같은 애노테이션을 붙일 수 있고, 컴파일러가 타입추론을 해준다.
    • Collection to Array
      List<String> list = Arrays.asList("Hello", "Java", "11");
      String[] array = list.toArray(String[]::new);
      
    • String 신규 method 추가
      • isBlank, lines, strip, stripLeading, stripTrailing, repeat 등 신규 String Method 추가

Java 17(LTS) 까지의 업데이트

  • Java 12, 13, 14
    • switch 문 개선 및 표준화(12~14)
      boolean isTodayHoliday = switch (day) {
          case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> false;
          case "SATURDAY", "SUNDAY" -> true;
          default -> throw new IllegalArgumentException("What's a " + day);
      };
      
    • Collectors.teeing 신규 메소드(12)
      • downstream collector에 대한 copmosite 제공
        Collector<T, ?. R> teeing(Collector<? super T, ?, R1> downstream1, Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger)
        
        double mean = Stream.of(1, 2, 3, 4)
                  .collect(Collectors.teeing(Collectors.summingDouble(i -> i), Collectors.counting()
                          , (sum, count) -> sum / count));
        
    • Pattern matching for instanceof
      Object s = "Hello World";
      // AS-IS
      if(s instanceof String) {
          String str1 = (String) s;
          System.out.println(str1);
      }
      // TO-BE
      if(s instanceof String str2) {
          System.out.println(str2);
      }
      
    • multi line string(13)
      • 텍스트 블록 기능 추가
        // AS-IS
        String JSON_STRING 
        = "{\r\n" + "\"name\" : \"Baeldung\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";
        // TO-BE
        String TEXT_BLOCK_JSON = """
        {
          "name" : "Baeldung",
          "website" : "https://www.%s.com/"
        }
        """;
        
    • NumberFormat 신규 method 추가(12, 14)
      • NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
    • record 키워드
      • immutable 객체를 생성하는 방법 중 하나로 toString, equals, hashCode 등에 구현 자동 제공
        public record User(int id, String password) {
          public User {
              if(password.isBlank() || password.length() < 10) {
                  throw new IllegalArgumentException("Password length");
              }
          }
        };
        User user = new User(1, "password1234");
        user.id();
        user.password();
        
  • Java 15
    • CharSequence 클래스에 메소드 추가
      • isEmpty
    • TreeMap 클래스에 메소드 추가
      • putIfAbsend, computeIfAbsent, ComputeIfPresent, compute, merge
    • Sealed Class
      • 상속관계에서 부모 클래스에서 자식 클래스의 집합을 제한하여 모델링을 간소화할 수 있도록 한다
        public abstract sealed class Person permits Employee, Manager { 
          //...
        }
        
    • Hidden Class
      • Runtime에서 클래스를 생성하고 reflection을 통해 간접적으로 사용하는 프레임워크에서 사용하기 위한 것
      • Hidden Class에서는 접근 제어를 member로 정의하며 다른 class와 독립적으로 unload할 수 있다
    • ZGC 운영 환경 사용할 수 있는 준비 완료
  • Java 16
    • InvokeHandler 인터페이스에 invokeDefault default method 정의 (Proxy Instances)
      interface HelloWorld {
          default String hello() {
              return "world";
          }
      }
      
      Object proxy = Proxy.newProxyInstance(getSystemClassLoader(), new Class<?>[] { HelloWorld.class },
          (prox, method, args) -> {
              if (method.isDefault()) {
                  return InvocationHandler.invokeDefault(prox, method, args);
              }
              // ...
          }
      );
      Method method = proxy.getClass().getMethod("hello");
      assertThat(method.invoke(proxy)).isEqualTo("world");
      
    • NIO SocketChannel, ServerSocketChannel에 AF_UNIX(Unix domain sockets) 추가
    • Stream.toList() 메소드 추가
      List<String> integersAsString = Arrays.asList("1", "2", "3");
      List<Integer> ints = integersAsString.stream().map(Integer::parseInt).collect(Collectors.toList());
      List<Integer> intsEquivalent = integersAsString.stream().map(Integer::parseInt).toList();
      

       

  • Java 17
    • Sealed Class 기능 완료
      • java.lang.Class에는 아래와 같이, 2개의 새로운 메서드가 추가 되어, 어떤 클래스가 sealed되어 있는지 확인하고, 허가된 서브클래스의 리스트를 가져오는 역할을 합니다
      • Class<?>[] getPermittedSubclasses(); boolean isSealed();
    • switch 문 패턴 매칭
    • DatagramSocket이 Multicast Group에 바로 join되어 사용 가능하도록 수정
    • Foreign Function & Memory API
      • JNI 대체를 위한 것으로 모든 네이티브 라이브러리를 쉽게 사용할 수 있도록 하는 것이 목표. 자바 프로그램이 네이티브 라이브러리와 상호 작용할 수 있는 기반 제공

Java 21 까지의 변화

  • Java 18: 비교적 작지만, 개발 환경을 쾌적하게 만들어주는 실용적인 기능이 추가되었다.
    • UTF-8 기본 인코딩 적용(JEP400): 한글 깨짐 현상등이 발생하였는데 file.encoding의 기본값이 모든 플랫폼에서 UTF-8로 통일되어 이식성 향상
    • 간단한 웹서버(Simple Web Server JEP408): 정적 파일을 손쉽게 제공할 수 있는 커맨드라인 툴 추가
      • 별도 톰캣 설정 없이 터미널에서 jwebserver 명령어만 입력하면 로컬 웹 서버가 실행되어 테스트나 로컬 개발 시 유용하다.
  • Java 19 & 20: 프로젝트 Loom 의 결과물들이 프리뷰로 등장
    • Virtual Thread 등장
      • 19에서 첫 프리뷰로 등장하였고 20에서 피드백을 받아 개선 21에 정식 기능
    • 다양한 패턴 매칭의 진화
      • switch문 패턴 매칭과 record 패턴 매칭이 계속해서 프리뷰로 제공되며 문법이 다듬어졌다.
  • Java 21
    • Virtual Thread(JEP444)
      • 기존의 OS 스레드(Platform Thread)와 달리 JVM내에 관리되는 매우 가벼운 스레드
      • 장점: 기존에 스레드를 생성하는 데 많은 리소스가 필요해 스레드 풍르 사용해야 했지만, 가상 스레드는 수백만개를 생성해 메모리나 컨텍스트 스위칭 비용이 매우 적다
      • 효과: Webflux와 같은 복잡성 없이, 기존의 동기식 코드를 그대로 작성하며 높은 처리량을 낼 수 있다.
    • Sequenced Collections(순서가 있는 컬렉션 - JEP431)
      • 컬렉션 프레임워크에 처음과 마지막 요소에 접근하는 표준화된 인터페이스가 추가되었다.
      • SequencedCollection, SequencedSet, SequencedMap
      • 제공되는 메소드: addFirst(), addLast(), getFirst(), getLast(), removeFirst(), removeLast(), reversed()
      • SequencedSet / SequencedMap특징
        • HashSet은 순서를 전혀 보장하지 않기 때문에 SequencedSet에 포함되지 않는다. 순서를 가지는 Set들만 이 새로운 인터페이스를 구현하도록 개편
        • LinkedHashSet/LinkedHashMap(입력 순서 보장): add 된 순서를 보장 - 시간복잡도 O(1)
          SequencedSet<String> set1 = new LinkedHashSet<>(); set1.add("C"); set1.add("B"); set1.add("A");
          System.out.println(set1.getFirst(); // C System.out.println(set1.getLast()); // A
          
        • TreeSet/TreeMap(값 기준 정렬 보장): 데이터의 값을 기준으로 정렬된 순서 보장 - 시간복잡도 O(logN)
          • 구조적으로 TreeSet이 구현하는 SortedSet 인터페이스가 이제 SequencedSet을 상속받도록 변경 됨
          • 따라서 정렬된 상태를 기준으로 getFirst()(가장 작은 값), getLast() (가장 큰값)
            SequencedSet<String> set2 = new TreeSet<>(); set2.add("C"); set2.add("B"); set2.add("A");
            System.out.println(set2.getFirst(); // A System.out.println(set2.getLast()); // C
            
    • Siwtch 패턴 매칭(JEP441)
      • if-else instanceof 체인을 깔끔한 switch 문으로 대체 가능, null처리도 switch 내부에서 가능
        switch(obj) {
            case Integer i -> System.out.println("Integer: " + i);
            case String s -> System.out.println("String: " + s);
            case null -> System.out.println("NULL!!");
            default -> obj.toString();]
        }
        
    • Record 패턴(JEP440)
      • record객체의 구성 요소를 분해아혀 바로 변수로 추출할 수 있는 기능이 도입되어 switch 패턴 매칭과 결합했을 때 좋은 시너지 발생
    • Generational ZGC (세대별 ZGC - JEP439)
      • Young Generation과 Old Generation을 분리하여 관리

Java 25까지의 정리: 개발자 생산성 향상, 성능 최적화에 초점

  • Java 22
    • Unnamed Variables & Patterns(_): 가독성을 위해 사용하지 않는 변수를 하이브리드 언어처럼 언더스코어(_) 표시(catch(Exception _)
    • [Preview] super() 호출 전, 유효성 검사와 같은 로직을 실행할 수 있게 하여 객체 초기화를 더 유연해졌다.
    • [Preview] Stream Gatherers: stream 에서 windowFixed, scan같은 복잡한 중간 연산을 커스텀 가능
  • Java 23
    • Markdown Documentation Comments: javadoc에서 HTMl 대신 MD를 사용할 수 있도록 했다.
    • [Preview] Primitive Types in patterns: instanceof, switch문에서 Primitive 타입이 사용할 수 있게 되었다
    • [Preview] Module Import Declarations: import module java.base; 한줄로 해당 모듈 내의 모든 패키지를 가저올 수 있게 되었다.
    • ZGC - Generational Mode Default: ZGC가 세대별 모드를 기본값으로 사용하여 성능 향상
  • Java 24
    • Stream Gatherers 정식화
    • Class-File API: Java 클래스 파일을 읽고 수정하는 API가 표준화 되었다. (바이트 버디같은 외부라이브러리 의존도를 낮출 수 있게 되었다)
    • [Experimental] Compact Object Headers: 64비트 아키텍트에서 객체 헤더 크기를 줄여 메모리 사용량을 절감하는 실험적 기능 도입, 클라우드 환경에서 매우 유용하다.
      • 왜 클라우드 환경에서 유용한가? 메모리 밀집도의 향상
      • 클라우드 환경에서는 CPU, RAM 사용량만큼 비용지불이 되기 때문
      • Heap 메모리 사용절감, CPU 캐시 효율 및 성능 향상, GC 부하 감소등으로 비용최적화 가능
  • Java 25
    • 언어 및 문법
      • Flexible Constructor Bodies: super() 호출 전 유효성 검사나 필드 초기화 로직을 넣을 수 있게 되었다.
      • Module Import 정식
      • Scoped Values 정식: ThreadLocal의 현대적 대안. 불변성을 보장하며 가상스레드 환경에서 훨씬 안전하고 효율적으로 데이터를 공유한다.
        • ThreadLocal의 한계 극복
          • 가변성: 누구나 set 메서드로 값을 바꿀 수 있기 때문에 추적 어려움
          • 무한 생명주기: remove()를 명시적으로 호출하지 않으면 메모리 누수 가능
          • 성능 저하: 가상 스레드 환경에서는 수만개의 스레드가 복사본을 갖게되어 메모리 부하가 커진다.
            • ThreadLocal은 각 스레드 내부에 ThreadLocalMap이라는 저장소를 갖고 새로운 스레드가 생성될 때 부모의 데이터를 자신의 저장소로 전부 복사한다.
        • ScopedValue의 핵심 특징
          • 특정 범위 내에서만 유효한 값을 의미한다
          • 불변성: 한번 설정된 값은 해당 범위 내에서 불변성을 갖기 때문에 멀티스레드 환경에서도 데이터 신뢰성 보장 가능
          • 자동 생명주기 관리: 별도 삭제코드를 작성할 필요 없이 블록이 끝나면 값은 자동으로 사라진다.
          • 가상스레드 최적화: 데이터를 스레드마다 복사하는 대신, 호출 스택을 통해 참조를 공유한다. 수백만개의 가상 스레드가 있어도 메모리 오버헤드가 거의 없다.
            • ScopedValue는 부모의 데이터를 전부 복사하는 것이 아닌 호출 스택의 프레임과 연결된 불변의 데이터 구조를 활용하여 값 자체는 힙에 하나만 존재하고, 이 값을 참조하라는 포인터(링크)가 추가된다.
    • 성능 및 런타임 최적화(인프라 효율)
      • Compact Object Headers 정식
      • AOT Method Profiling: 이전 실행의 프로파일링 정보를 저장했다가 재시작 시 활용, 이를 통해 애플리케이션의 웜업 시간이 드라마틱하게 단축된다.
    • 모니터링 및 진단 (운영 안전성)
      • JFR Method Timing & Tracing

출처