이펙티브자바 item55. 옵셔널 반환은 신중히 하라

Jiwon·2022년 5월 29일
0

이펙티브자바

목록 보기
10/10
post-thumbnail

item55. 옵셔널 반환은 신중히 하라

메서드가 특정 조건에서 값을 반환할 수 없ㅇ르 때 취할 수 있는 선택지
1. 예외를 던진다.
2. null을 반환한다.

예외는 진짜 예외적인 상황에서만 사용해야 하며
예외를 생성할 때 스택 추적 전체를 캡처하므로 비용도 만만치 않음

null을 반환하면 이런 문제가 생기지 않지만, 별도의 null처리 코드를 추가해야 한다.

null처리를 무시하고 반환된 null 값을 어딘가에 저장해두면 언젠가 NullPointException이 발생할 수 있기 때문.

자바 버전 8 이상부터
Optional는 null이 아닌 T타입 참조를 하나 담거나, 혹은 아무것도 담지 않을 수 있다.
아무것도 담지 않은 옵셔널은 '비었다'라고 말한다.
어떤 값을 담은 옵셔널은 '비지 않았다'라고 한다.

옵셔널은 원소를 최대 1개 가질 수 있는 '불변'컬렉션.

public static <E extends Comparable<E>> E max(Collection<E> c){
	if (c.isEmpty())
    	throw new IllegalArgumentException("빈 컬렉션");
        
	E result = null;
    for(E e : c)
    	if(result == null || e.compareTo(result) > 0 )
        	result = Objects.requireNonNull(e);
            
	return result;
}

이 메서드는 빈 컬렉션을 건네면 IllegalArgumentException을 던진다.
아이템 30에서도 Optional를 반환하는 편이 더 낫다고 이야기 했는데,
그렇게 수정한 모습은 다음과 같음.

public static<E extends comparable<E>>
	Optional<E> max(Collection<E> c) {
   	if (c.isEmpty())
    	return Optional.empty();
        
    E result = null;
    for (E e : c)
    	if (result==null || e.compareTo(result) > 0)
        	result = Objects.requireNonNull(e);
            
    return Optional.of(result);
    }

이 코드에서는 두 가지 팩터리를 사용했다.
빈 옵셔널은 Optional.empty()로 만들고,
값이 든 옵셔널은 Optional.of(value)로 생성
Optional.of(value)에 null을 넣으면 NullPointerException을 던지니 주의.

null값도 허용하는 옵셔널을 만들려면 Optional.ofNullable(value)를 사용하면 된다.
옵셔널을 반환하는 메서드에서는 절대 null을 반환하지 말 것

옵셔널은 검사 예외와 취지가 비슷

즉, 반환 값이 없을 수도 있음을 API사용자에게 명확히 알려준다.

메서드가 옵셔널을 반환한다면 클라이언트는 값을 받지 못했을 때 취할 행동을 선택해야 한다.
그중 하나는 기본값을 설정하는 방법.

String lastWordInLexicon = max(words).orElse("단어 없음...");

또는 예외 던지기

Toy myToy = max(toys).orElseThrow(TemperTantrumException::new);

isPresent메서드.

안전밸브 역할의 메서드로,
옵셔널이 채워져 있으면 true, 비어 있으면 false를 반환.

streamOfOptionals
	.filter(Optional::isPresent)
    .map(Optional::get)

옵셔널에 값이 있다면 (Optional::isPresent) 그 값을 꺼내
(Optional::get) 스트림에 매핑.

자바 9에서는 Optional에 stream() 메서드가 추가되었다.
Optional을 Stream으로 변환해주는 어댑터.
옵셔널에 값이 있으면 그 값을 원소로 담은 스트림으로,
값이 없다면 빈 스트림으로 변환한다.
이를 Stream의 flatMap 메서드와 조합하면 앞의 코드를 다음처럼 바꿀 수 있음

streamOfOptionals
	.flatMap(Optional::stream)

컬렉션, 스트림, 배열, 옵셔널 같은 컨테이너 타입은 옵셔널로 감싸면 안 된다.

빈 Optional List를 반환하기보다는 빈List를 반환하는게 좋다.

옵셔널을 컬렉션의 키, 값, 원소나 배열의 원소로 사용하는게 적절한 상황은 거의 없다.


핵심정리
값을 반환하지 못할 가능성이 있고, 호출할 때마다 반환값이 없을 가능성을 염두에 둬야하는 메서드라면 옵셔널을 반환해야 할 상황일 수 있다.
하지만 옵셔널 반환에는 성능 저하가 뒤따르니, 성능에 민감한 메서드라면 null을 반환하거나 예외를 던지는 편이 나을 수 있다. 그리고 옵셔널을 반환값 이외의 용도로 쓰는 경우는 매우 드물다.

profile
과연 나는 ?

0개의 댓글