코딩과 결혼합니다

null을 처리하는 방법 본문

2세/Spring

null을 처리하는 방법

코딩러버 2024. 2. 4. 18:10
728x90

null

특별한 값을 나타내는데 사용되는 키워드. 아무런 값도 가지지 않음을 나타내며, 참조 타입 변수가 어떠한 객체도 참조하지 않을 때 주로 사용된다. null은 기본 타입에는 사용할 수 없고, 오직 참조 타입 변수에만 할당할 수 있다.

null을 사용하기 전에 해당 변수가 null인지 아닌지를 체크하는 것이 중요한데, 그렇지 않으면 NullPointException이 발생할 수 있다. 참조 변수 타입에 null을 할당하면, 해당 변수는 객체를 참조하지 않게 되므로 사용할 수 있는 메서드나 속성에 접근할 수 없다.

 

null 을 다루는 방법

Optional 클래스

java 8부터 도입된 클래스로, null-safe한 프로그래밍을 지원한다.
Optional을 사용하면 값이 존재하지 않을 수 있는 경우에도 NullPointerException을 방지할 수 있다.
Optional<TotalRating> checkRating = totalRatingRepository.findByUserId(evaluated_user);

나는 위의 코드와 같이 null이 아닌 경우에 repository에서 조건에 만족하는 데이터들을 꺼내오도록 하였다.

 

Null 체크

Object 클래스의 isNull 메서드나, StringUtils 클래스의 isEmpty 메서드를 사용하여 null의 여부를 확인하여 처리한다.
if (existingUser.isEmpty()){
    throw new CustomException(ErrorMessage.NON_EXISTENT_USER, HttpStatus.BAD_REQUEST);
}

나는 보통 값이 null 일 때에 Exception을 반환하도록 처리하였다.

 

// 캐시에서 평가 정보 조회
UserRatingsResponseDto cachedResponse = redisTemplate.opsForValue().get(cacheKey);
if (cachedResponse != null) {
    return cachedResponse;
}

// 캐시에 없는 경우 기존 로직으로 평가 정보 조회
UserRatingsResponseDto response = ratingService.getUserRatings(evaluated_user, page - 1, size);

// 조회한 평가 정보를 캐시에 저장
redisTemplate.opsForValue().set(cacheKey, response);

캐싱을 하였을 때에도 null을 확인하는 과정을 거쳤는데, null 이 아닌 경우에는 캐시에 저장된 값을 그대로 반환하고, 

null인 경우에는 기존의 로직을 통하여 평가 정보를 조회한 뒤에 그 값을 캐시에 저장하도록 하였다.

 

이와 같이 null이 아닌 경우에만 해당 블록을 실행하도록 할 수 있다.

 

@Nullable 어노테이션 사용하기

매개변수나 반환 타입에 null이 허용됨을 표시할 수 있다.
public void someMethod(@Nullable String nullableParam) {
    // null 처리 로직
}

위와 같이 적용해 볼 수 있다.

@Column(nullable = false)
private String content;

나는 보통 이와 반대로 동작하는 어노테이션 @Cloumn을 사용하여 필드에 null이 허용되지 않음을 표시하였다. 그리고 null 값을 저장하려고 할 때에 "내용을 입력해 주세요"와 같은 메시지를 반환하도록 예외처리를 해주었다.


tip - Optinal

옵셔널을 바로 반환하지 않고 사용하기.

 

//같은 이름의 중복회원 x
Optional<Members> result = memberRepository.findByName(members.getName());
result.ifPresent(m -> {
    throw new IllegalArgumentException("이미 존재하는 회원입니다.");
});

 

 

memberRepository.findByName(members.getName())
        .ifPresent(m -> {
            throw new IllegalArgumentException("이미 존재하는 회원입니다.");
        });
검색해보니 아래는 메서드 체이닝 방식이라고 한다. 아래와 같이 쓰는 이유로는

1. 가독성
2. 성능 : 전자는 findByName() 메서드를 호출하여 결과를 가져온 후, ifPresent() 메서드에서 다시 한 번 결과를 확인해야 한다. 이는 불필요한 메서드 호출로 성능 저하를 가져올 수 있다.