자바 List의 null 체크 (with isEmpty())

반응형
728x90
반응형

상황

TestDto testDto = testList.get(0);

 

자바 List의 0번째 데이터를 set 해줘야하는 코드를 만났다. testList에는 어떤 데이터가 들어있는지 모른다. (null 일수도있고, 몇개의 row가 들어가있을 수 있다.) 위 testList.get(0) 을 실행하는 부분에서 NullPointerException을 만났다.

 

 

분석

NullPointerException이 발생하여 null 체크를 추가하였다. testList는 외부 API에서 얻어온 데이터가 들어있는 List라서 어느 특정 실행 시점에서 null인 testList에 get 메서드를 호출했기 때문에 발생하는 문제였다.

if (testList != null) {
	TestDto testDto = testList.get(0);
}

 

위 코드를 추가하니, testList가 null이 아닌 경우에만 get 메소드를 호출한다. 하지만 문제는 또 발생했다. 또다시, 해결했다고 생각했던 NullPointerException을 만났다.

 

디버깅 결과 : testList는 Null이 아닌, "" (빈문자열)

디버깅으로 데이터 확인 결과, testList가 "" (빈문자열) 이였다. 이 경우는 화면단에서 받아온 데이터였기 때문에 빈문자열인 경우를 만났다.

참고) [] : select 쿼리를 통해 데이터를 가져왔을 testList가 조회된 데이터가 없을 경우

 

if (testList != null && !testList.isEmpty()) {
	TestDto testDto = testList.get(0);
}

 

isEmpty() 메소드까지 추가하였더니, 더이상 결과가 없을 경우에 NullPointerException 가 발생하지 않았다. isEmpty() 메소드 호출 이전 null 체크를 해준 이유는 리스트가 null인 경우에 isEmpty() 메소드를 호출하면 NullPointerException발생하기 때문이다.

 

여기서 한가지 더, size() 메소드를 호출할 경우에도 마찬가지로 != null 이 선행되어야한다. 그렇지 않으면 리스트가 null 인 경우에 NullPointerException 가 발생한다.

해결은 했지만 리스트의 어떤 상황에서 어떻게 빈값 체크를 해야하는지 헷갈렸다. 지금 바로 분석해보자.

 

 

정리

CASE1. isEmpty()

// 주소값 참조 상태 (인스턴스 생성을 했기 때문)
List<TestDto> testList = new ArrayList<>(); // testList = []

if (testList.isEmpty()) {
	Log.info("[] 일 경우에는 isEmpty() 메소드로 체크");
}
// 화면(front)에서 받아온 데이터 디버깅시, 리스트가 빈문자열인 경우
AbcDto.getList(); // ""

if (testList.isEmpty()) {
	Log.info(""" 일 경우에는 isEmpty() 메소드로 체크");
}

 

주의할 점은, testList가 null인 경우 isEmpty()를 호출하면 이때에도 NullPointerException 가 발생한다. 그러므로, isEmpty() 메소드를 호출하기 전에 null 체크가 선행되어야 한다.

 

 

CASE2. != null

// 주소값 참조 X
List<TestDto> testList = null;

if (testList != null) {
	Log.info(null 일 경우에는 != null로 체크");
}

 

null 주의하자! Null 체크만 하면 안된다. testList가 [] 또는 "" 일때에 != null 을 통과해서 후에 NullPointerException을 만날 수 있다. 따라서 초반에 언급한 코드로 체크하는 것을 권장한다.

 

  • 권장
if (testList != null && !testList.isEmpty()) {
	TestDto testDto = testList.get(0);
}

 

CASE3. ObjectUtils.isEmpty()

ObjectUtils 클래스의 isEmpty() 를 호출하면 위 권장된 소스를 하나의 메소드 호출로 해결할 수 있다.

ObjectUtils.isEmpty() 메소드 코드를 보자.

 

public static boolean isEmpty(@Nullable Object obj) {
        if (obj == null) {
            return true;
        } else if (obj instanceof Optional) {
            return !((Optional)obj).isPresent();
        } else if (obj instanceof CharSequence) {
            return ((CharSequence)obj).length() == 0;
        } else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        } else if (obj instanceof Collection) {
            return ((Collection)obj).isEmpty();
        } else {
            return obj instanceof Map ? ((Map)obj).isEmpty() : false;
        }
    }

 

null 체크와 isEmpty()를 동시에 실행하고있다. '권장' 코드와 CASE3.ObjectUtils.isEmpty() 호출 방법 중 선택하면 될 것 같다.

 

 

마무리

해당 포스팅을 통해서, 리스트를 체크하는 상황에서 NullPointerException 을 꼭 회피할 수 있도록 하자.

 

 

 

 

 

 

반응형

Designed by JB FACTORY