JPA Repository는 왜 단일 Entity 반환시 Optional<>을 사용할까?

doma17·2024년 1월 9일
0

spring-jpa

목록 보기
1/1

📌 결론

단일 Entity를 반환할 때 Optional<>을 사용하는 것은 해당 Entity가 존재하지 않을 수 있는 상황을 고려하여 안전성을 확보할 수 있기 때문이다.

  • 매우 기본적인 문제이지만, Java에 대한 밑바탕 없이 접근한다면 헷갈릴 수 있기에 정리했다
  • 이해를 위해 Java8 버전부터 추가된 Optional<> 에 대해서 파악할 필요가 있다

Optional이란?

  • Optional은 제네릭 클래스의 일종으로서 값이 null일 수 있는 상황에서 사용한다

Optional은 다음과 같은 메서드를 가지고 있다.

  1. of(value) / ofNullable(value):

    • of(value): 주어진 값으로 Optional 객체를 생성한다.
      • 값이 null이면 NullPointerException이 발생한다
    • ofNullable(value): 주어진 값으로 Optional 객체를 생성한다
      • 값이 null이어도 예외가 발생하지 않는다
    	Optional<String> nonNullableOptional = Optional.of("Hello");
    	Optional<String> nullableOptional = Optional.ofNullable(null);
  2. isPresent():

    • 값이 존재하는지 여부를 판단한다
    • 값이 존재하면 true, 그렇지 않으면 false를 반환한다.
      	Optional<String> optional = Optional.of("Hello");
    	if (optional.isPresent()) {
          // 값이 존재하는 경우 처리
    	}
  3. ifPresent(consumer):

    • 값이 존재하는 경우에만 주어진 동작을 수행한다
    • Consumer 함수형 인터페이스를 인자로 받는다
    	Optional<String> optional = Optional.of("Hello");
    	optional.ifPresent(value -> System.out.println("Value : " + value));
    	// Value : Hello
  4. get():

    • 값이 존재하면 해당 값을 반환하고, 그렇지 않으면 NoSuchElementException이 발생한다
    • 일반적으로 isPresent()를 함께 사용하는 것이 권장된다
      	Optional<String> optional = Optional.of("Hello");
    	String value = optional.get();
      	// value = "Hello"
  5. orElse(other) / orElseGet(supplier) / orElseThrow(exceptionSupplier)

    • orElse(other): 값이 존재하면 해당 값을 반환하고, 그렇지 않으면 주어진 기본값을 반환한다
    • orElseGet(supplier): 값이 존재하면 해당 값을 반환하고, 그렇지 않으면 Supplier로 제공된 값을 반환한다
    • orElseThrow(exceptionSupplier): 값이 존재하면 해당 값을 반환하고, 그렇지 않으면 주어진 예외를 발생시킨다
    	Optional<String> optional = Optional.of("Hello");
    	String result1 = optional.orElse("Default");
        String result2 = optional.orElseGet(() -> getDefaultValue()); // 값이 없더라도 기본 값을 넣어주는 것이다.
        String result3 = optional.orElseThrow(() -> new NoSuchElementException("No value present"));
  6. filter(predicate):

    • 값이 주어진 조건(predicate)과 일치하면 현재 Optional을 반환하고, 그렇지 않으면 빈 Optional을 반환한다
      	Optional<String> optional = Optional.of("Hello");
        Optional<String> filteredOptional = optional.filter(value -> value.length() > 5);
  7. map(mapper) / flatMap(mapper):

    • map(mapper): 값이 존재하면 주어진 매핑 함수를 적용하고, 결과를 포함하는 Optional을 반환한다
    • flatMap(mapper): 값이 존재하면 주어진 플랫맵 함수를 적용하고, 결과를 포함하는 Optional을 반환한다 (매핑 함수가 Optional을 반환할 수 있음)
      	Optional<String> optional = Optional.of("Hello");
        Optional<Integer> lengthOptional = optional.map(String::length);

JpaRepository

  • JpaRepository에 대한 설명은 생략..
  • 그렇다면 이러한 Optional을 사용함에 있어서 어떠한 이점이 있을까?
    • null을 반환하거나 null 체크를 별도로 하지 않아도 되므로 코드의 가독성과 안전성이 향상된다
      • → 항상 null이 아님을 체크해야 함으로 무분별한 if 문 사용을 초래할 수 있다
    • NullPointerException을 방지하고 코드 안정성을 향상시킬 수 있다.
    • 값이 존재하지 않을 수 있는 경우에 대한 명시적인 처리를 제공한다.
    • 실수로 null을 처리하지 않는 과정을 줄일 수 있다.
      • Optional<?> 사용시 실제 인스턴스로 변환하는 과정에서 null 처리를 필요로 한다.
Optional<Entity> entity = repository.findById(id);

if (optionalEntity.isPresent()) {
    Entity entity = optionalEntity.get(); // Optional<>에 담겼던 실제 인스턴스를 반환한다.
    // 메인 로직
} 
else {
		// Entity가 존재하지 않는 경우 처리 로직
		// e.g. throw new Exception();
}

📌 마치며

단일 Entity를 반환할 때 Optional<>을 사용하는 것은 해당 Entity가 존재하지 않을 수 있는 상황을 고려하여 안전성을 확보할 수 있기 때문이다. null에 대해 불확실성이 존재하는 상황 또는 예상치 못한 NullPointException에 대한 대응을 위해 사용이 권장된다.

profile
나태한 동물

0개의 댓글