[ 자바 8의 지원일자 ]

  • 무료 지원 일자 : 20214-03 ~ 2022-03
  • 유료지원 일자 : 2030-12
  • 무료 대안( Amazon Corretto, AdoptOpenJDK 등에서 2026년까지 지원 계획 )

[ 호환 스프링 부트 ]

  • Spring Boot 호환 : 1.5x ~ 2.7x
  • 안정 적인 버전 :  자바 8과는 2.7.x(18) 버전이 안정적

[ JVM & GC ]

  • Parallel 스트림에 포크/조인 풀 사용

[ 특징 및 주요 변경 사항 ]

 

1. Lambda expression(람다 표현식)

 

  • Lambda expression(람다 표현식) : 아래와 같이 람다식을 쓸 수 있게 변경되었습니다. 람다 식은 함수형 프로그래밍 언어로 함수 자체를 값처럼 전달할 수 있도록 해줍니다.
  • 문법
형식 예시 비고
(파라미터)→{본문} (int x, int y) → x + y 타입 추론 가능시 타입 생략 가능
파라미터 1개 + 타입추론 + 본문 1줄 리턴생략 x → x*x 괄호 생략 가능
본문 다중 라인 (a,b) → { int r = a*b; return r; } 중괄호 필수
메서드 참조 String::toUpperCase, Integer::sum 람다식 간결화
  • 코드
List<Integer> list = Arrays.asList(1,2,3,4,5);
		Collections.sort(list, (a,b)->b - a);
		for(int num : list)
			System.out.print(num + " ");// 출력결과 : 5 4 3 2 1

2. Functional interface(함수형 인터페이스)

  • 추상 메서드가 단 하나만 존재하는 인터페이스로 @FunctionalInterface 어노테이션을 사용해 쓸 수 있다.

 

3. Default method(디폴트 메서드)

  • 디폴트 메서드는 간단하게 말하면, 기존 코드를 건드리지 않고 인터페이스에 새 동작을 넣고 싶을 때 사용할 수 있습니다. 기존에는 인터페이스 자체에 구현을 넣을 수 없어 API 확대가 어려웠습니다. 이를 해결하기 위해 default 키워드로 인터페이스에 몸체를 바로 넣을 수 있습니다.
public interface A {
    void abstractMethod();            // 여전히 추상 메서드
    default void log(String msg) {    // ← 디폴트 메서드
        System.out.println("[A] " + msg);
    }
}
// 다중 상속시, 명시적으로 super 키워드로 해결
interface L {
    default void log(){ System.out.println("L"); }
}
interface R {
    default void log(){ System.out.println("R"); }
}
class Impl implements L, R {
    @Override public void log(){      // 직접 해결
        L.super.log();                // or R.super.log()
        System.out.println("Impl");
    }
}

 


 

4. Stream(스트림)

  • 스트림은 데이터 원본(컬렉션, 배열, I/O 등)을 선언적 파이프라인으로 처리할 수 있게 해주는 API입니다. 반복문에서 사용하는 임시 변수를 제거하여 가독성이 향상되고 병렬 처리가 가능합니다.
  • 구성요소
    • 생성 : stream(), IntStream.range(), Files.lines()
    • 중간 연산 : filter, map, sorted, peek( 무한 체인, lazy )
    • 최종 연산 : collect, reduce, count, forEach → 파이프라인 실행 트리거
  • 일반적인 반복 문과 차이점은 아래와 같습니다.
항목 반복문 스트림
선언적 코드 X O
Lazy 처리 X O
병렬 전환 수동 스레딩 작성 parallel() 한 줄로 가능
성능(소량) 빠름 약간 느릴 수 있음

 

 

  • 코드 예시
List<String> words = List.of("java", "lambda", "stream", "blog");
long result = words.stream()        // ① Source
                   .filter(w -> w.length() > 3)  // ② Intermediate
                   .map(String::toUpperCase)
                   .distinct()
                   .count();       // ③ Terminal

 


5. Optional(옵셔널)

  • Optioanl은 NPE 발생 가능성을 컴파일 타임에 노출하여, 오류를 빨리, 명시적으로 처리하게 합니다. 그러나 오남용하면 오히려 복잡성과 오버헤드가 늘어납니다.
  • Optional<T>는 값이 있을 수도, 없을 수도 있는 컨테이너로, 타입 수준에서 없음으로 표현합니다.
  • 코드 예시
// Spring Data findById
User user = userRepo.findById(id)
        .orElseThrow(() -> new EntityNotFoundException("사용자 없음"));

// Optional + Stream (Java 8 방식)
List<String> mails = users.stream()          // List<User>
    .map(User::getPrimaryEmail)              // Optional<String>
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList());

6. 새롭게 추가된 날짜 API

  • 자바 8 java.time API는 가독성, 불변, 스레드 안전을 모두 만족시키게 업데이트되었습니다.
범주 클래스 특징
날짜 전용 LocalDate YYYY-MM-DD(타임존 X)
시간 전용 LocalTime hh:mm:ss.nnnnnnnn(타임존 X)
날짜 + 시간 LocalDateTime 가장 자주 쓰임(타임존 X)
시점 Instant UTC 기준 1970-01-01부터 ns 단위 offset
오프셋 포함 OffsetDateTime, OffsetTime +09:00 같은 오프셋 포함
타임존 포함 ZonedDateTime LocalDateTime + ZoneId 완전체
기타 Year, YearMonth, MonthDay, Clock, ZoneId  
  • 코드 예시 
// 생성 & 조작
LocalDate today = LocalDate.now();                 // 2025‑04‑30
LocalDate payday = today.withDayOfMonth(25);       // 이번 달 25일
LocalDate nextMonthFirst = today.with(TemporalAdjusters.firstDayOfNextMonth());

LocalDateTime meeting = LocalDateTime.of(2025, 5, 2, 14, 0);
LocalDateTime plus90 = meeting.plusMinutes(90);    // 15:30

// 포매팅 / 파싱 (DateTimeFormatter)
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm");
String s = fmt.format(meeting);                    // "2025.05.02 14:00"
LocalDateTime parsed = LocalDateTime.parse("2025‑05‑02 14:00", fmt);

 


 

7. CompletableFuture(컴플리터블 퓨처)

  • java 5에서 추가된 Future의 단점을 모두 개선한 CompletableFuture가 등장했다.
  • Non-blocking : 결과가 준비될 때까지 스레드를 묶어두지 않음
  • 함수형 체이닝 : 람다와 결합해 Promise 스타일 파이프라인을 구성
  • 조합 : 여러 비동기 작업을 AND / OR 방식으로 조립 가능
  • 완료 알림 : 성공, 실패, 취소 이벤트를 한곳에서 다룹니다.
  • 비동기 + 이벤트 기반 API를 표준 라이브러리에서 바로 제공합니다.
  • thenApply, thenCompose, allOf, exceptionally 등 풍부한 조합자(Combinator)로 콜백 지옥을 방지합니다.
  • CPU 바운드, I/O 바운드 작업 분리가 용이합니다.
CompletableFuture
        .supplyAsync(() -> {
            sleep(300);          // 시간이 오래 걸리는 작업
            return "hello";
        })
        .thenApply(String::toUpperCase)  // 후속 변환 (논블로킹)
        .thenAccept(System.out::println); // HELLO

supplyAsync : 별도 스레드에서 Supplier 실행.
thenApply   : 완료된 결과를 받아 변환.
thenAccept  : 최종 소비(출력).

// 두 계산 병렬 → 합산
CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> heavy(20));
CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> heavy(22));

a.thenCombine(b, Integer::sum)
 .thenAccept(sum -> log("합계=" + sum)); // 42

 


 

8. JVM의 변화

  • Java 8이 나오면서 JVM의 메모리 영역 중에 Permanent Generation 이 완전히 제거되고, Metaspace 메모리 영역이 새로 도입되었습니다.
  • 메모리 관리 개선: 고정 크기의 PermGen으로 인한 제한사항을 해결하고, 동적으로 확장 가능한 메모리 모델을 제공합니다.
  • 가비지 컬렉션 부담 감소: Metaspace는 가비지 컬렉션 관점에서 더 효율적으로 설계되었습니다. G1(Garbage-First) 가비지 컬렉터의 개선으로 대규모 힙 관리가 더 효율적으로 이루어졌습니다.
  • 클래스 언로딩 개선: 클래스 언로딩 메커니즘이 개선되어 동적 클래스 로딩/언로딩이 많은 애플리케이션의 성능이 향상되었습니다.
  • 64비트 아키텍처 최적화: 현대적인 64비트 시스템에서 네이티브 메모리를 더 효율적으로 활용할 수 있게 되었습니다.

 

+ Recent posts