CS/Java

Java 8 특징

leah-only 2025. 4. 7. 19:01

Java 8 

Java 8에 추가된 내용

  • lambda
  • optional

 


Lambda

함수를 하나의 표현식으로 나타낸 것

함수형 프로그래밍 언어에서 사용되는 개념으로 메서드에 이름이 없어 익명 함수라고도 불린다.

괄호()와 화살표를 이용해 함수를 선언한다. 

람다식으로 선언된 변수명은 다른 변수명과 중복될 수 없다. 

장점

  • 코드를 간결하게 만들 수 있다. 

단점

  • 재사용이 불가능하다.
  • 디버깅이 어렵다. 
  • 재귀로 만들경우 부적합하다. 

예시

List<String> list = Arrays.asList("banana", "apple", "cherry");

// 기존
Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});

// 람다
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));

함수형 인터페이스 (Functional Interface)

추상 메서드가 딱 하나만 있는 인터페이스이다. 

자바의 람다는 이런 인터페이스를 기반으로 동작한다. 

@FunctionalInterface 어노테이션은 선택이지만 붙이면 안전하게 검사가 가능하다. 

Java 8 부터 표준 함수형 인터페이스를 다양하게 제공한다. 

 

👇 함수형 인터페이스

@FunctionalInterface
interface MyPrinter {
    void print(String message);
}

 

👇 이걸 직접 구현하려면

MyPrinter printer = new MyPrinter() {
    @Override
    public void print(String message) {
        System.out.println("출력: " + message);
    }
};

 

✅ 그런데 자바 8부턴 이걸 람다식으로 간단히 표현 가능

MyPrinter printer = message -> System.out.println("출력: " + message);
  • 자바가 자동으로 "message -> {...}" 이 부분을 print(String)에 맞춰서 이해한다. 
  • 이유는 MyPrinter가 함수형 인터페이스라서 (추상 메서드가 하나니까)

 

대표적인 함수형 인터페이스

Supplier<T> T get() 결과만 반환 (입력 없음)
Consumer<T> void accept(T t) 입력만 받고 반환 없음
Function<T, R> R apply(T t) 입력 받고 변환해서 반환
Predicate<T> boolean test(T t) 조건 검사해서 true/false 반환
Runnable void run() 매개변수 없고 반환도 없음

Default Method

인터페이스내에서 구현이 가능한 메서드

재정의가 가능하다.

 

 

✅ 사용 예시

public interface Greeting {
    void sayHello();

    default void sayBye() {
        System.out.println("안녕히 가세요~");
    }
}

public class KoreanGreeting implements Greeting {
    @Override
    public void sayHello() {
        System.out.println("안녕하세요!");
    }
    // sayBye()는 안 써도 됨 (default method니까)
}

 


Stream API

자바의 Collection 데이터를 함수형 스타일로 선언적으로 처리할 수 있게 하는 API

for, if 쓰면서 반복하는 걸 filter(), map(), collect() 같은 체이닝 메서드로 깔끔하고 간결하게 읽기 좋게 바꿔주는 기술

선언형이란 데이터를 처리하는 구현 코드 대신, 질의로 표현하는 것을 말한다. 

 

🔄 중간 연산

filter() 조건 필터링
map() 값 반환
sorted() 정렬
distinct 중복 제거
limit(n)/skip(n) 앞에 n개 가져오기 / 건너 뛰기

 

🎯 최종 연산 (스트림 종료)

collect(Collectors.toList()) 리스트로 수집
count() 개수 세기
forEach() 하나씩 처리
anyMatch(), allMatch() 조건 만족 여부 확인
reduce() 누적 계산 (합계 등)

 

🔍 코드

List<String> highRatingMoviesName = 
    movies.stream()
          .filter(m -> m.getRating() > 7) // 평점 7 이상 영화 선택
          .sorted(comparing(Movie::getRating)) // 평점 순으로 정렬 (오름차순)
          .map(Movie::getName) // 영화명 추출
          .collect(Collectors.toList()); // 리스트에 저장

 


Optional<T>

null을 직접 다루지 않도록 만들어진 null-safe 컨테이너 클래스이다. 

Optional은 '존재할 수도 있지만 안 할 수도 있는 객체' 즉 'null이 될 수도 있는 객체'를 감싸고 있는 래퍼 클래스이다. 

Optional을 사용하면 NPE를 유발할 수 있는 null을 직접 다루지 않아도 된다. 

 

✅ Optional 생성

Optional<String> opt1 = Optional.of("현진"); // null이면 예외 발생
Optional<String> opt2 = Optional.ofNullable(possiblyNullValue); // null 허용
Optional<String> opt3 = Optional.empty(); // 빈 Optional

 

✅ 값 꺼내기

Optional<String> nameOpt = Optional.of("Java");

// 값이 있으면 꺼내기
String name = nameOpt.get(); // ❌ 비어 있으면 예외 발생

// 안전한 방식들
nameOpt.ifPresent(n -> System.out.println(n)); // 값이 있을 때만 실행
String result = nameOpt.orElse("기본값");       // 값이 없으면 기본값 반환
String result2 = nameOpt.orElseGet(() -> "디폴트"); // 지연 실행
String result3 = nameOpt.orElseThrow(() -> new IllegalArgumentException("없음!")); // 예외 발생

 

 

Optional.of() 절대 null 아닌 값만
Optional.ofNullable() null도 허용
get() 값 꺼냄 (null이면 예외)
ifPresent() 값 있을 때만 실행
orElse() / orElseGet() 기본값 제공
map() / flatMap() 값 가공 (스트림처럼 체이닝)

 


참고 :  https://github.com/devSquad-study/2023-CS-Study

https://velog.io/@skyepodium/%EC%9E%90%EB%B0%94-Java-8-%EB%B2%84%EC%A0%84-%ED%8A%B9%EC%A7%95

'CS > Java' 카테고리의 다른 글

Reflection  (1) 2025.04.24
Generic  (0) 2025.04.23
자바의 비동기 처리  (0) 2025.04.07
Error & Exception  (0) 2025.04.04
Boxing & UnBoxing  (0) 2025.03.28