다음과 같이
lambda 표현식은 많은 개발자들이 일상적인 개발에서 사용하고 있으며, 특히 온라인 환경에서는 널리 활용됩니다. 하지만 lambda를 사용할 때는 데이터 검증을 충분히 해야 하며, 그렇지 않으면 빈 포인터 예외(NPE)가 발생할 수 있습니다. 이번 글에서는 최근 온라인 환경에서 발생한 빈 포인터 예외를 해결하는 과정을 공유해 보겠습니다.
다음 코드를 살펴보겠습니다:
public static void main(String[] args) {
TestVo testVo = new TestVo();
List<TestVo> testVoList = Lists.newArrayList(testVo);
Map<String, Integer> collectMap = testVoList.stream().collect(Collectors.toMap(TestVo::getName, TestVo::getAge));
System.out.println(collectMap);
}
이 코드에는 두 가지 잠재적인 빈 포인터 예외가 있습니다. 첫 번째로, testVoList가 비어 있는 경우입니다. 데이터베이스에서 가져온 리스트라면 반드시 빈 포인터를 확인해야 합니다.
두 번째로, toMap 메서드의 두 번째 파라미터(즉, TestVo::getAge, 맵의 값)가 null인 경우입니다. 이 경우에도 빈 포인터 예외가 발생합니다. toMap 메서드는 내부적으로 merge 메서드를 호출하며, 이 메서드는 값이 null일 수 없습니다.
이 문제를 피하기 위해 다음과 같이 코드를 수정할 수 있습니다:
Map<String, Integer> collectMap = testVoList.stream().collect(Collectors.toMap(TestVo::getName,
t -> {
if (t.getAge() == null) {
return 0;
} else {
return t.getAge();
}
}));
또한, age 타입을 기본 타입 int로 변경하면 문제를 방지할 수 있습니다. 기본 타입 int의 초기값은 0이기 때문입니다. 이는 또한 기본 타입과 래퍼 클래스 간 변환 시 주의해야 할 빈 포인터 예외의 또 다른 예시입니다.
다음과 같은 코드는 빈 포인터 예외를 발생시킵니다:
Integer a = null;
int b = a;
따라서, 기본 타입과 래퍼 클래스 간 변환 시 반드시 빈 포인터를 확인해야 합니다. 또한, 기본 타입과 래퍼 클래스는 서로 다른 타입으로 간주되므로, 다음 두 메서드는 서로 다른 메서드로 간주됩니다:
private void processNumber(Integer num) {
System.out.println(num + num);
}
private void processNumber(int num) {
System.out.println(num * num);
}
이런 중복 정의는 호출 측에 혼란을 줄 수 있으니 피하는 것이 좋습니다.