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 |