Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

DS's TechBlog

[Java] Optional과 findById 본문

Java & Spring

[Java] Optional과 findById

dsjo 2024. 4. 13. 23:19

JPA의 findById로 User 엔티티를 가져오려 할 때, 아래와 같은 에러가 발생했습니다.

User user = userRepository.findById(id);

"Incompatible types. Found: 'java.util.Optional<com.haedal.haedalweb.domain.User>', required: 'com.haedal.haedalweb.domain.User'"

 

Optional<User> 타입으로 받아야 하는데, User 타입으로 받아서 문제가 생겼다고 합니다.

그럼, Optional은 무엇이며, 왜 Optional로 반환해야 하는지 알아보겠습니다.

 

Optional이란?

A container object which may or may not contain a non-null value. If a value is present, isPresent() returns true. If no value is present, the object is considered empty and isPresent() returns false.Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (returns a default value if no value is present) and ifPresent() (performs an action if a value is present).

 

oracle의 공식 문서에 따르면, 

Optional 클래스null이 아닌 값을 포함할 수도 있고 포함하지 않을 수도 있는 컨테이너 객체입니다. 값이 있는 경우, isPresent() 메서드는 true를 반환합니다. 값이 없는 경우, 이 객체는 비어 있는 것으로 간주되며 isPresent()false를 반환합니다. 값의 존재 여부에 따라 다른 메서드들이 제공되는데, 예를 들어 orElse() 메서드는 값이 없을 때 기본값을 반환하고, ifPresent() 메서드는 값이 있을 때 특정 행동을 실행합니다.

API Note:Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

 

또한, Optional은 주로 메서드 반환 타입으로 사용되며, "결과가 없음"을 명확하게 나타낼 필요가 있고, null을 사용하면 오류가 발생할 가능성이 높은 경우에 사용됩니다. Optional 타입의 변수는 절대 null이어서는 안 되며, 항상 Optional 인스턴스를 가리켜야 합니다.

 

Optional 반환?

위의 말에 따르면, Optional은 주로 메서드 반환 타입으로 사용되며, null을 사용하면 오류가 발생할 가능성이 높은 경우에 사용된다고 합니다. 왜 그럴까요?

 

메서드가 특정 조건에서 값을 반환할 수 없을 때, null을 반환한다고 가정해봅시다.

그러면, null을 반환할 수 있는 메서드를 호출할 때는, 별도의 null 처리를 해주어야 합니다. 그렇지 않다면, NullPointerException이 프로그램 어딘가에서 발생할 가능성이 생깁니다.

User user = userRepository.findById(id);

if (user == null) {
	// null 일 때 코드 ...
}
else {
	// null 아닐 때 코드 ...
}

그래서, 위와 같이 null 처리를 해줘야 합니다. 

 

그런데, 여기서 문제가 생깁니다.

1. 어떤 메서드가 null을 반환할 가능성이 있는지 모릅니다.

2. 그렇다면, 모든 메서드 호출 부분에서 null 처리를 해야 합니다.

-> 굉장히 비효율적으로 보입니다. 또한, null 처리 구문을 빼먹을 가능성도 있어 보입니다.

 

이러한 문제를 Optional을 반환함으로써 해결할 수 있습니다.

1. Optional을 반환하면, 메서드의 반환 값이 없을 수도 있음을 API 사용자가 명확히 알 수 있습니다.

2. Optional을 사용하면, 값의 존재를 확인하지 않고 값을 바로 사용할 수 없습니다. 이는 API 사용자가 isPresent(), isEmpty(), orElse(), orElseThrow() 등의 메서드를 통해 값을 안전하게 처리하도록 강제합니다.

-> findById는 id를 기준으로 값을 찾지 못 했을 때, null을 반환해야 할 것 입니다. 하지만, null 대신 Optional.empty() 를 반환하게 하면서, 빈 값을 안전하게 처리할 수 있도록 반환타입을 Optional로 정해놓은 것이었습니다.

 User user = userRepository.findById(id)
                .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + id));

위와 같이 처리함으로써, NullPointerException의 위험 없이 안전하게 처리할 수 있게 됩니다.

 

주의점

  1. Collection, Stream, 배열, 옵셔널 같은 컨테이너 타입은 이미 빈 값을 표현할 수 있기 때문에, Optional로 감싸지 않는 것이 좋습니다. Optional도 엄연히 객체이므로 오버헤드가 발생할 수 있기 때문입니다.
  2. Optional을 반환하는 메서드에서는 절대 null을 반환하면 안됩니다. null을 반환한다면, Optional을 도입한 취지와는 정반대의 행동이게 됩니다.

 

 

 

 

참고

Joshua Bloch. 『Effective Java 3/E』. 이복연(역). 프로그래밍인사이트, 2018.

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Optional.html