Java

Optional을 파라미터로 전달하지 말자

Jaime.Lee 2023. 2. 3. 04:38

자바 프로그래밍을 하다보면 Optional을 파라미터로 전달했을 때 컴파일러가 경고(노란줄)를 표시합니다. (IntelliJ에서는 표시해주는데 다른 IDE는 어떤지 잘 모르겠네요)

경고를 확인하기 위해 간단한 코드를 작성해보면,

  public void foo(String nullable) {
    bar(Optional.of(nullable));
  }

  private void bar(Optional<String> s) {
    // do something
  }
'Optional<String>' used as type for parameter 's' 

바로 이런 내용을 확인할 수 있습니다.

그렇다면 왜 Optional을 파라미터로 전달하면 안 되는 것일까요?

결론부터 말씀드리면 장점보다 단점이 많기 때문입니다.

먼저 장점으로는 전달할 당시에 별 생각 없이 전달할 수 있다는 점이 있습니다. 어차피 전달할 메서드에서 처리할 것이기 때문에 메서드에 해당 변수나 값에 대한 처리를 위임할 수 있습니다.

반대로 메서드 내에서 조건절 작성을 강제하도록 유도하는 것은 비생산적입니다. 또한 컴파일러 입장에서 Optional로 감싸는 것은 불필요한 wrapping을 유발하는 경우가 생길 수 있습니다. 게다가 nullable한 파라미터와 비교하여 Optional은 처리하는데 비용이 더 많이 듭니다. 마지막으로 필수 파라미터를 null로 전달할 가능성이 높아져 실수를 유발하기 쉽습니다.

애초에 단순하게 생각하면 Optional을 파라미터로 전달한다는 것 자체가 세 가지 상태를 가질 수 있음을 나타냅니다. (1) Optional 자체가 null인 경우, (2) Optional.isPresenttrue인 경우(실제 값을 가지는 경우)와 (3) false인 경우(Optional.empty()) 이렇게 총 세 가지 입니다.

  public void foo(String nullable) {
    bar(null); // (1)
    bar(Optional.of("nonnull")); // (2)
    bar(Optional.ofNullable(nullable)); // (3)
  }

  private void bar(Optional<String> s) {
    if (s != null) { // Optional을 null과 비교해야 함, 역시 컴파일러가 경고로 알려줌

    }
  }

(1)의 경우 바로 위에 작성한 코드처럼 Optionalnull과 비교하는 로직이 추가되어야 합니다. null을 전달하는 경우를 방지하기위해 @NotNull 애너테이션 등을 사용한다면 NotNull이지만 Nullable한 아이러니한 상황이 연출됩니다.

  private static void test(@NotNull Optional<String> s) {
    if(!s.isPresent()) { // NotNull이지만 s가 가진 value 자체는 null이 될 수 있음

    }    
  }

따라서 Optional을 파라미터로 전달하는 대신 필요한 경우 전달한 파라미터를 메서드 내부에서 Optionalwrapping 해주어야 합니다.

사실 의도적으로 Optional을 전달하는 경우는 흔치 않을 거 같은데, 코드를 작성하다가 특정 부분을 메서드로 추출하는 단축키를 눌렀다가 자동으로 Optional 파라미터를 전달하게 되는 경우가 있는데, 이 메서드를 다른 누군가가 재활용한다면 의도에 맞게 사용되지 않을 수 있으므로 꼭 주의하셔야 합니다.