본문으로 건너뛰기
개발 머꼬
개발 노트Java
hohyeon.dev31

Integer를 int로 자동 언박싱하다가 NullPointerException이 난 이유

  • #Common Pitfall
  • #Engineering Note
  • #Java

문제 발생

DB에서 nullable한 정수 컬럼을 Integer 필드로 매핑해 쓰고 있었는데, 그 값이 null인 레코드에서 특정 계산 로직을 실행하자 NullPointerException이 발생했습니다.

Integer discount = order.getDiscount(); // DB에서 null일 수 있음
int finalPrice = order.getPrice() - discount; // 여기서 NPE

원인 분석

Java 5부터 도입된 **오토박싱/언박싱(autoboxing/unboxing)**은 래퍼 타입(Integer)과 기본 타입(int)을 섞어 쓸 수 있게 해주는 편의 기능입니다. 컴파일러가 필요한 곳에 자동으로 .intValue() 호출(언박싱) 또는 Integer.valueOf() 호출(박싱)을 삽입합니다.

문제는 discountInteger 타입인데 값이 null인 상태에서, order.getPrice() - discount처럼 기본 타입과의 뺄셈 연산에 쓰이면 컴파일러가 자동으로 discount.intValue()를 호출하도록 코드를 변환합니다. null 참조에 .intValue()를 호출하는 것과 동일하므로 NullPointerException이 발생합니다 — 코드에는 .intValue()라는 글자가 전혀 보이지 않는데도 실제로는 그 호출이 숨어서 일어나고 있어, 원인을 찾기가 까다롭습니다.

같은 문제가 삼항 연산자에서도 은근히 자주 발생합니다.

Integer a = null;
int b = 1;
int result = condition ? a : b; // condition이 true면 NPE — 삼항 연산자의 결과 타입 통일 과정에서 언박싱이 일어남

해결 방안

  1. 연산에 쓰기 전에 항상 null 여부를 확인합니다.
int discountValue = (discount != null) ? discount : 0;
int finalPrice = order.getPrice() - discountValue;
  1. Java 8+라면 Optional로 nullable 값을 명시적으로 다루는 것도 방법입니다 — Optional.ofNullable(discount).orElse(0).
  2. DB 컬럼이 실제로 null을 허용하지 않는다면, 매핑 자체를 Integer 대신 int로 하는 것이 더 안전합니다 — 기본 타입은 애초에 null이 될 수 없으므로 이 문제 자체가 발생할 여지가 없습니다. null 가능성을 표현해야 하는 필드에만 래퍼 타입을 씁니다.
  3. IDE의 정적 분석(null 관련 검사)이나 @Nullable/@NonNull 애너테이션을 일관되게 붙여두면, 이런 종류의 실수를 컴파일/린트 시점에 미리 잡아낼 수 있습니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.