java

Optional

주다애 2023. 7. 9. 15:44

본 게시물은 프로그래머스 FOO님의 실무 자바 개발을 위한 OOP와 핵심 디자인 패턴을 듣고 작성된 게시물입니다.

 

💡 Optional

Java8에서 제공하는 문법으로 NPE를 가독성 좋게 처리해준다.

Optional을 사용하는 이유는 API 호출을 유창하게(fluent) 할 수 있기 때문이다.

 

자바의 Null

Null은 참조할 주소 값이 없는 것을 의미한다.

자바에서 null을 참조하는 오브젝트의 메서드를호출하게 되면 NPE가 발생한다.

하지만 메서드가 static 이라면 예외가 발생하지 않고 정상 실행된다.

null을 참조하는 레퍼런스 변수로 객체의 인스턴스 메서드를 호출할 때 발생하는 예외 NPE(NullPointerException)이 있다.

public class NullMain {
    public static String getStr() {
        return "hi";
    }

    public static void main(String[] args) {
        String str = getNull();
        NullMain m = null;
        System.out.println(m.getStr().toUpperCase());
        System.out.println(str);
        System.out.println(str.toUpperCase());

    }
    private static String getNull() {
        return null;
    }
}

위의 코드 중 str.toUpperCase()에서 NPE가 발생한다.

m.getStr().toUpperCase()가 예외가 발생하지 않는 이유는 getStr()이 static 메서드이기 때문이다.

 

우리는 메서드 호출 결과가 null이면 어떤 자세를 취해야 할까?

1. 해당 클래스의 인스턴스 생성하여 메서드 호출 계속하기

2. 예외 던지기

주로 2번 방식을 택한다고 한다.

 

다시 Optional로 돌아와서

결국, Optional은 NPE를 효율적으로 처리해주는 방법이다.

public class MapRepository {
    private Map<String, String> map = new HashMap<>();

    MapRepository() {
        map.put("EXIST_KEY", "value");
    }

// Optional 사용
    public Optional<String> getOptionalValue(String key) {
        return Optional.ofNullable(map.get(key));
    }
    
    public String getValue(String key) {
        return map.get(key);
    }
}

getOptionalValue메서드가 Optional 타입을 반환해주고있다.

이러한 경우는 isPresentOrElse()나 orElseThrow()와 같은 메서드를 사용할 수 있다.

Optional<String> optional = mapRepository.getOptionalValue("NOT_EXIST_KEY");

// Optional 사용하고 null 체크1
optional.ifPresentOrElse(
        str -> System.out.println(str.toUpperCase()), // Optional이 empty가 아닐 때
        () -> {
            throw new RuntimeException("키가 존재하지 않습니다.");
        }
);

// Optional 사용하고 null 체크2
String string1 = mapRepository.getOptionalValue("NOT_EXIST_KEY").orElseThrow(
        () -> {throw new RuntimeException("키가 존재하지 않습니다.");}
);
System.out.println(string1.toUpperCase());

> ifPresentOrElse()를 사용하면 처음 조건은 Optional이 비어있지 않을 때, 두 번째 조건은 Optional이 비어있을 때를 처리

> orElseThrow()는 Optional이 비어있을 때 예외를 던져줌

 

이렇게는 쓰지 말자

Optional이 좋기는 하지만 쓰지 않을 때와 같을 때도 있다.(Anti Optional 패턴)

// Optional 타입의 객체 opt 생성

if (!pt.isPresent()) {
// 예외 던지기
}
else {
// 로직 처리하기
]

기존의 null 체크 방식과 다를 것이 없다.

또한 몇 가지 피해야 할 사항이 있다.

 

1. Optional 변수에 null을 할당하지 말자. 값이 없다면 isEmpty() 메서드 활용하자

return null; 대신 return Optional.empty(); 권장

2. Optional을 필드로 사용하지 말자. Optional은 반환 타입을 위해 설계되었다. 필드가 비어있는지 확인하고 싶다면 boolean 타입을 사용하자

3. isPresent() 사용하지 말자(위의 예시). 대신 ifPresent()나 ifPresentOrElse()사용하자(위의 예시)

4. Optional을 인자로 사용하지 말자. 2번과 비슷한 이유

 

 

 

참고문헌

https://www.latera.kr/blog/2019-07-02-effective-optional/#8-optional-%EC%9D%84-%ED%95%84%EB%93%9C%EC%9D%98-%ED%83%80%EC%9E%85%EC%9C%BC%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EC%A7%80-%EB%A7%90-%EA%B2%83

 

Optional 제대로 활용하기 - Increment

Optional을 올바르게 사용하기 위해 공부한 내용을 정리합니다. 개요 getter에 Optional을 사용하는 것이 좋은지에 대해, Java 언어 아키텍트인 Brian Goetz가 Stackoverflow에 작성한 답변(링크)입니다. 당연히

www.latera.kr

https://medium.com/javarevisited/we-do-things-wrong-4-anti-patterns-when-using-optional-1dbfdfd8739a

 

We Do Things Wrong! 4 Anti-Patterns When Using Optional

Four common anti-patterns that arise when utilizing the functional features of Java 8 without understanding the underlying concepts.

medium.com

 

'java' 카테고리의 다른 글

동일성 vs 동등성  (0) 2023.08.17
stream API + Optional  (0) 2023.07.15
stream API  (0) 2023.07.10
람다식  (0) 2023.07.09
상속  (0) 2023.07.08