티스토리 뷰

개발

Java8 - Optional 자료형을 사용하는 이유

기억고양이 2023. 2. 17. 01:50
반응형

 

Optional은 Java8에서 새로 추가된 API이다. 처음봤을때 매우 당황스런 놈이었다.

Java8에 새로 추가된 요소들중 람다식이니 함수형 인터페이스다 뭐다 하는 놈들중 하나가 Optional 이다.

 

 

현재까지 내가 이해한 내용은 이 값이 비어있는 상태로 반환될 수 있음표시하는 것이다.

추가로 Null체크하기가 좋고(이거는 사용방법을 더 찾아봐야 한다..), 소스를 명확하게 작성할 수 있다는게 강점인것 같다.

 

하지만 소스상으로 구현이 가능하다고 해서 마구잡이로 사용하면 안된다고 한다. (아니 그럼 안되게 만들던가)

 

내가 내린 결론은 Optional은 잘 알고 써야지 모르면 그냥 안쓰는게 낫다는 것이다.

 

잘 써보고 싶어서 스택오버플로우에 있던 내용 + 내가 이해한걸 대충 정리한다.


"이 값이 비어있는 상태로 반환될 수 있음" 을 설명하면..

 

public String tempString (String test) {...} public Optional<String> tempString (String test) {...}
이걸 보는 개발자는 보통 String이 넘어올 거라고 생각하지 Null이 올거라곤 기대하지 않는다. 하지만 메소드를 보면 빈 값이 올수도 있음을 "인지" 할 수 있다는 것이다.

그리고 나와 비슷한 궁금증을 가진 사람이 있어 한글로 옮겨봤다. 결론은 1번처럼 쓰는게 좋다고 하더라.

심지어 답변자가 Oracle에서 일하는 JDK 개발자여서 더 신뢰가 가는 답변이었다.

 

답변 말투는 내 맘대로 각색했다.

 

질문 >

https://stackoverflow.com/questions/23454952/uses-for-optional

 

* Java8을 사용한지 6개월이 지났고 API가 변경된 것들이 꽤 즐거운데요, 하지만 Optional을 사용할 때만 자신감이 떨어지네요.

  Null이 나오는 모든곳에 사용하고 싶어지지만, 어떨때는 전혀 쓰고싶지 않아요. 둘 사이에서 갈팡질팡 하게 되네요.

 

정작 사용하면서도 의문인게,

  1. 가독성이 좋은지도 모르겠고
  2. 정말로 Null에 안전한건지도 모르겠고
  3. 그저 오버헤드만 더 일으키는건 아닌지

확신이 서지 않아요. 다음 예제들 처럼 쓰는데 Optional이 언제 유용한건지 여러분의 의견이 궁금합니다.

 

1. null이 반환될수도 있는 public 메소드의 리턴타입으로 사용할때

 

public Optional<Foo> findFoo(String id);

 

2.  null일수도 있는 파라미터로 사용될때

 

public Foo doSomething(String id, Optional<Bar> barOptional);

 

3. bean의 멤버로 사용될때

 

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

 

4. (일반적으로 이렇게 쓸려고 하진 않지만) 컬렉션에서 사용할때 입니다.

 

List<Optional<Foo>>

 

5. 추가로 컬렉션에서 filter()를 사용해 null이나 기타 값들을 제거할 수 있는데 더 좋은 용도가 있을까요?


답변 >

Optional은 반환값이 "없다"를 indicate(표시)하기 위해 설계되었습니다. 이걸 쓰면 끊기지 않는 유연한 메소드 호출이 가능합니다.


1. 1번케이스가 가장 알맞은 사용방법입니다.

IntStream.findFirst() 같은 절대 null일수가 없는것을 리턴하는게 더 좋은 방법입니다.



2. null 이 될수도 있는 파라미터로 사용해도 작동은 되지만 좀 어설픈 방법입니다.
String 과 두번째 String이 올수도 있는 메소드가 있다고 칩시다.

 

다음처럼 사용해도 됩니다.

 

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

 

차라리 Null을 던지는게 더 낫겠네요.

 

foo("bar", "baz");
foo("bar", null);

 

더 좋은 방법이 있습니다. 단일 파라미터를 받고 메소드 오버로딩을 사용하는 거죠.

 

foo("bar", "baz");
foo("bar");

 

Optional 용법에 제한은 없지만, 굳이 안써도 위 케이스처럼 쓰는게 제일 편합니다.



3번 4번
필드 변수나 데이터 구조에 써버리면 잘못 사용 된 API로 판단합니다.

    첫번째로 위에 언급했던 대로 optional의 설계 철학에 위반되는 사항입니다.
    두번째로 어떤값도 추가할 수 없습니다.

Optional에서 값이 없는걸 다루는 3가지 방법이 있는데 :

  • 값을 대체하는 방법을 제공하거나
  • 주어진 값을 대체하는 함수를 불러주거나
  • 또는 예외를 던지는 방법입니다.

클래스의 필드 변수로 사용할거라면 변수 초기화 때 위의 3가지 방법을 쓰거나, 필드 값을 할당할때 이런 방법을 쓸겁니다.

 

List의 값으로 쓰고싶다면 그냥 값을 추가하지 않으면 됩니다. 굳이 이렇게 쓸 필요가 없습니다. (그냥 Null로 쓰거나 new로 초기화 하면 되지 않냐 이런 의미인듯)


하지만 이 중 누군가는 컬렉션에 Optional을 저장하는 예제를 들 수도 있겠지만, 이런건 피하는것이 가잫 좋습니다.

(굳이 Optional 꾸역꾸역 넣어가면서 소스 이상하게 쓰지말라는 소리 같다.)


그리고 4번같은 경우 List<Optional<Foo>>가 잘못되었다고 한거고,

반대로 Optional<List<Foo>>는 잘못된 방법이 아닌것 같더라. List가 Null일 수도 있으니깐...

 

이 답변을 본 이후로 아주 조오금 Optional이란 놈에 대해서 알게된거 같다.

특히 Null체크를 쉽게 해보고 싶은데 실전엔 잘 못써먹겠음. (Stream도 비슷한 이유로 잘 못쓰겠다)

 

 

 

 

좀 더 실패하고 예제를 찾아가면서 알아가야 할 API인것 같다.

언제 또 정리 할 수 있을까......

반응형