개발노트

4. [Spring Boot] Optional 사용 (NullPointerException 방지하기) 본문

서버 개발/Spring Boot

4. [Spring Boot] Optional 사용 (NullPointerException 방지하기)

mroh1226 2024. 4. 16. 10:13
반응형

Optional<>

자바 개발자라면 누구나 한 번쯤 NullPointerException(NPE) 문제를  직면하게됩니다.

이런 문제를 해결하기 위한 방법 중 하나가 Optional입니다.

NullPointerException을 방지하려면 모든 객체 참조에 대해 null 체크를 수행해야 합니다.

이는 코드를 복잡하게 만들고 가독성을 해치며 실수를 유발할 수 있습니다.

Optional은 이 문제에 대한 해결책을 제공합니다.

Optional은 값이 존재하지 않을 수 있는 상황을 고려하여 설계된 컨테이너 클래스입니다.

Optional로 객체를 감싸고, 값이 존재하지 않을 때 NPE를 방지할 수 있습니다.


Optional을 사용하는 이유

  1. 명시적인 Null 처리: Optional은 값이 없을 때 명시적으로 처리할 수 있습니다. 이는 코드의 안정성을 높이고 NPE를 방지합니다.
  2. 가독성: Optional은 코드를 더 읽기 쉽게 만듭니다. 값이 없을 때의 처리를 쉽게 파악할 수 있으며, 이는 코드의 가독성을 향상시킵니다.
  3. 메서드 체이닝: Optional은 메서드 체이닝을 지원합니다. 이를 통해 여러 메서드를 연속적으로 호출하고, 그 결과로 얻은 값을 안전하게 처리할 수 있습니다.
  4. 함수형 프로그래밍과의 호환성: Optional은 함수형 프로그래밍의 개념과 잘 어울립니다. 이를 통해 함수형 스타일로 코드를 작성하고, null 처리를 간결하게 할 수 있습니다.
Optional 사용 예시
import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        // Optional을 사용하여 값이 존재하는 경우와 없는 경우를 다루는 예제

        // 값이 있는 경우
        Optional<String> optionalValue = Optional.of("Hello, Optional!");
        optionalValue.ifPresent(value -> System.out.println("값이 있습니다: " + value));

        // 값이 없는 경우
        Optional<String> emptyValue = Optional.empty();
        emptyValue.ifPresent(value -> System.out.println("값이 있습니다: " + value));
    }
}
  • 이 예제에서는 Optional을 사용하여 값이 존재하는 경우와 없는 경우를 다루는 방법을 보여줍니다.
  • 첫 번째로, of 메서드를 사용하여 값이 있는 Optional 객체를 생성하고, ifPresent 메서드를 사용하여 값이 존재하는 경우에만 해당 값을 출력합니다.
  • 두 번째로, empty 메서드를 사용하여 값이 없는 Optional 객체를 생성하고, ifPresent 메서드를 사용하여 값이 존재하지 않는 경우 아무 작업도 수행하지 않습니다.
  • 이를 통해 Optional을 사용하여 NullPointerException을 방지하고 안전하게 코드를 작성할 수 있습니다.
예시2. (Spring Boot)
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/{userId}")
    public ResponseEntity<User> getUserById(@PathVariable Long userId) {
        Optional<User> optionalUser = userRepository.findById(userId);
        
        if (optionalUser.isPresent()) {
            return ResponseEntity.ok(optionalUser.get());
        } else {
            return ResponseEntity.notFound().build();
        }
    }
}
  • 위의 코드에서는 "/api/users/{userId}" 엔드포인트로부터 사용자를 조회하는 API를 구현합니다.
  • UserRepository의 findById 메서드를 사용하여 사용자를 조회하고, Optional을 사용하여 조회한 사용자가 존재하는지 확인합니다.
  • 조회한 사용자가 존재하는 경우에는 ResponseEntity.ok를 사용하여 사용자를 반환하고, 사용자가 존재하지 않는 경우에는 ResponseEntity.notFound를 사용하여 404 상태 코드를 반환합니다.
  • 이 예제에서는 사용자가 존재하지 않을 수 있는 상황을 Optional을 사용하여 명시적으로 처리하고 있습니다.
  • 이를 통해 API 사용자에게 사용자가 존재하지 않는 경우에 대한 정보를 명확하게 전달할 수 있습니다.

Optional이 불필요 한 경우

Optional은 값이 존재하지 않을 수 있는 경우에 사용되는 컨테이너 클래스입니다. 따라서 단일 객체에 대해서는 주로 Optional을 사용하고, 여러 객체가 포함된 컬렉션인 List나 Array등에는 일반적으로 Optional을 적용하지 않습니다. 이는 다음과 같은 이유 때문입니다:

  1. 컬렉션의 크기 유연성: List나 Array은 여러 개의 객체를 포함할 수 있습니다. 이들 컬렉션은 크기가 0인 경우도 있을 수 있고, 여러 개의 객체를 포함할 수 있습니다. Optional은 단일 객체에 대한 값의 존재 유무를 나타내는 용도로 사용되므로, List나 Array과 같은 컬렉션에는 적합하지 않습니다.
  2. 컬렉션의 반복성: List나 배열과 같은 컬렉션은 반복 가능한(iterable) 객체입니다. 이들은 for-each 루프나 스트림 API를 사용하여 컬렉션의 각 요소를 반복할 수 있습니다. Optional은 단일 객체에 대한 값의 존재 여부를 나타내므로, 컬렉션의 각 요소에 대해 개별적으로 Optional을 적용하는 것은 바람직하지 않습니다.
  3. 널 값의 대체 불필요: List나 배열 등의 컬렉션은 일반적으로 null을 포함하지 않습니다. 컬렉션이 비어 있는 경우에는 크기가 0인 컬렉션이 생성되고, 요소가 포함된 경우에는 요소가 포함된 컬렉션이 생성됩니다. 따라서 컬렉션에 대한 null 체크와 대체 로직은 보통 불필요합니다.

따라서 List나 Array과 같은 컬렉션에는 일반적으로 Optional을 적용하지 않습니다. 대신 컬렉션이 비어 있는지 여부를 직접 확인하거나, 요소가 존재하는지 여부를 확인하는 등의 방법을 사용하여 컬렉션을 처리합니다. Optional은 단일 객체에 대한 값의 존재 여부를 나타내는 용도로 사용됩니다.

반응형
Comments