본문 바로가기
language/java

Java Optional 남용 문제 완벽 이해하기

by 죄니안죄니 2026. 5. 28.
반응형

Java Optional 남용 문제 완벽 이해하기

Java 8에서 Optional 이 등장한 이후 많은 개발자가:

“null 대신 전부 Optional 쓰면 좋은 거 아냐?”
 

라고 생각하기 쉽습니다.

하지만 실제 실무에서는:

Optional 남용
 

이 매우 흔한 문제입니다.

특히:

  • JPA Entity
  • DTO
  • 필드 선언
  • 메서드 파라미터
  • Collection 내부

등에서 잘못 사용하면:

  • 성능 문제
  • 직렬화 문제
  • 가독성 저하
  • 프레임워크 충돌

까지 발생할 수 있습니다.

Java 공식 문서와 실무 스타일에서도:

Optional은 “제한적으로” 사용하는 것이 권장
 

됩니다.

이번 글에서는:

  • Optional 설계 목적
  • 왜 남용이 문제인가
  • Optional 필드 문제
  • JPA 충돌
  • Optional 파라미터 문제
  • Collection과 Optional
  • 성능 문제
  • 실무 권장 패턴

까지 깊게 정리해보겠습니다.


1. Optional의 원래 목적

매우 중요합니다.

Optional은 원래:

“메서드 반환값”
 

용도로 설계되었습니다.


2. 핵심 철학

즉:

“값이 없을 수도 있음”
 

을 호출자에게 명확히 전달하기 위한 것.


3. 가장 적절한 사용 예

 
Optional<User> findUser(Long id)
 

4. 의미

유저가 없을 수도 있음
 

을 타입 자체로 표현.


5. 그런데 문제는 여기서 시작

많은 개발자가:

Optional을 모든 곳에 사용
 

하기 시작함.


6. 대표적인 안 좋은 예

 
class User {

    Optional<String> name;
}
 

7. 왜 문제일까?

매우 중요.

Optional은 원래:

값 자체가 아니라
“반환 컨테이너”
 

개념에 가까움.


8. Optional 필드 문제

대표 문제:

  • 메모리 증가
  • 직렬화 문제
  • 프레임워크 호환 문제
  • 코드 복잡도 증가

9. 메모리 문제

예:

 
Optional<String>
 

도 결국:

객체 하나 추가 생성
 

입니다.

즉:

필드마다 wrapper 객체 추가
 

가능.


10. DTO에서 문제

예:

 
class UserResponse {

    Optional<String> name;
}
 

11. JSON 직렬화 문제 가능

예전 Jackson 환경에서는:

Optional 자체 구조 노출
 

문제 발생 가능.

예:

 
{
  "name": {
    "present": true
  }
}
 

같은 이상한 결과 가능했던 시절 존재.


12. 현재는 어느 정도 개선

Jackson 의 JDK8 module 등으로 개선 가능.

하지만 여전히:

DTO 필드 Optional은 보통 비추천
 

입니다.


13. JPA Entity에서 특히 위험

매우 중요.


14. 안 좋은 예

 
@Entity
class User {

    Optional<String> name;
}
 

15. 왜 문제일까?

Hibernate / JPA는 기본적으로:

일반 필드 매핑 기대
 

합니다.

Optional은:

wrapper 객체
 

라서:

  • 프록시 처리
  • reflection
  • bytecode enhancement

등과 충돌 가능.


16. 그래서 실무에서는 보통

 
private String name;
 

로 두고:

 
Optional<String> getName()
 

형태 선택.


17. Optional 파라미터 문제

매우 흔한 남용.


18. 안 좋은 예

 
saveUser(Optional<String> name)
 

19. 왜 안 좋을까?

호출하는 쪽이:

 
saveUser(Optional.of(name))
 

처럼 불필요하게 복잡해짐.


20. 차라리 더 나은 방식

 
saveUser(String name)
 
nullable 허용 여부 명확화
 

가 보통 더 나음.


21. Collection 안의 Optional도 주의

예:

 
List<Optional<User>>
 

22. 왜 문제일까?

실무에서는 보통:

복잡도 폭증
 

가능.

대부분 경우:

빈 리스트
 

가 더 자연스러움.


23. Optional<Collection<T>> 도 주의

예:

 
Optional<List<User>>
 

24. 왜 비추천할까?

이미:

빈 리스트 자체가 “값 없음”
 

을 표현 가능.

즉:

이중 의미
 

생김.


25. Optional.get() 남발 문제

매우 흔함.


26. 안 좋은 예

 
optional.get()
 

27. 왜 문제일까?

결국:

NPE 대신
NoSuchElementException
 

로 바뀐 것뿐.


28. 즉 Optional 의미 상실

null 체크와 다를 게 없어짐
 

29. Optional은 “체이닝”이 핵심

좋은 예:

 
userOpt
    .map(User::getAddress)
    .map(Address::getCity)
    .orElse("Unknown");
 

30. Optional 성능 문제

대부분 상황에선 큰 문제 아님.

하지만:

  • 대량 객체 생성
  • hot loop
  • GC 민감 환경

에서는 비용 존재 가능.


31. Primitive Optional 존재 이유

대표:

 
OptionalInt
OptionalLong
OptionalDouble
 

32. 왜 따로 있을까?

boxing/unboxing 비용 감소
 

목적.


33. Optional은 Serializable 아님

매우 중요.

일부 Java 버전/환경에서는:

직렬화 이슈
 

가능.

즉:

  • Session 저장
  • Cache 저장
  • Entity 저장

등에서 주의 필요.


34. Spring/JPA 실무 스타일

보통 권장 패턴:

위치권장 여부
반환 타입 적극 권장
Entity 필드 비추천
DTO 필드 보통 비추천
파라미터 비추천
Collection 내부 비추천

35. 왜 반환 타입은 좋은가?

Optional의 핵심 목적이:

“호출자에게 null 가능성 전달”
 

이기 때문.


36. 좋은 예

 
Optional<User> findById(Long id)
 

37. 안 좋은 예

 
User findById(Long id)
 

null 가능성 숨김
 

38. Optional 남용의 진짜 문제

매우 중요.

Optional은:

가독성 개선 도구
 

인데,

남용 시 오히려:

가독성 파괴
 

가능.


39. 안 좋은 코드 예

 
Optional<Optional<List<User>>>
 

40. 이런 구조가 생기면

보통:

설계 이상 신호
 

인 경우 많음.


41. Optional과 Null의 관계

중요.

Optional은:

null 제거 도구
 

가 아니라,

null 가능성 명시 도구
 

에 더 가까움.


42. 실무에서 가장 많이 쓰는 패턴

대표:


Repository 반환

 
Optional<User> findById(...)
 

Stream 결과

 
findFirst()
max()
min()
 

기본값 처리

 
.orElse(...)
 

43. 실무에서 자주 하는 실수

1) 필드 전체 Optional화

비추천.


2) Optional.get() 남발

Optional 의미 상실.


3) Optional<List<T>>

빈 리스트로 충분한 경우 많음.


4) 파라미터 Optional 사용

호출 코드 복잡도 증가.


44. 핵심 흐름 요약

Optional 목적
=
반환값 null 가능성 표현

↓
필드/파라미터 남용 시
오히려 복잡도 증가
 

45. 가장 중요한 핵심 한 줄

Optional은
“모든 곳에 쓰는 null 대체제”가 아니라,
“반환값의 null 가능성을 표현하는 도구”에 가깝다
 

입니다.


46. 정리

Optional은 매우 강력한 도구지만,
남용하면 오히려 코드 품질이 나빠질 수 있습니다.

실제로는:

  • 함수형 프로그래밍
  • Stream API
  • null 안정성
  • 반환 타입 설계
  • JPA/Spring 호환성

전체와 연결되는 중요한 Java 설계 개념입니다.

특히 실무에서는:

  • 반환 타입만 Optional 사용
  • Optional.get() 지양
  • Optional<List<T>> 지양
  • Entity/DTO 필드 Optional 주의
  • map/flatMap 적극 활용

을 정확히 이해하는 것이 매우 중요합니다.

다음 글에서는:

함수형 프로그래밍 패러다임 이해

를 불변성(immutability), side effect, pure function, declarative programming, Java Stream 철학까지 포함해서 깊게 정리해보겠습니다.

반응형

댓글