* 개발 환경
- IDE : IntelliJ IDEA
- backend : Spring Boot 3.3.5
- others : Postman
1. 문제
백엔드 개발을 진행하면서, 프론트엔드에서 값을 입력하지 않은 채로 데이터를 백엔드로 보낼 경우 어떻게 처리되는지 궁금했다. 특히 임시 저장 기능을 구현할 때, 값이 변하지 않는 항목들에 대한 처리 방안을 고민하게 되었다. 그래서 실제로 테스트를 통해 입력되지 않은 값이 백엔드에서 어떻게 나타나는지를 확인해 보았다.
사실 가장 궁금한 것은, 입력 누락 시 서비스단에서 데이터를 처리해야 하는데 NullPointerException 에러가 발생해서 짚고 넘어가면 좋겠다 싶어서 글을 작성하게 되었다.
@RestController
public class BlogController {
@PostMapping("/api/post")
public void post(@RequestBody BlogDTO blogDTO) {
System.out.println(blogDTO);
}
}
import lombok.Data;
@Data
public class BlogDTO {
private String title;
private String author;
private int price;
}
우선 백엔드는 Controller, DTO를 위와 같이 간단히 만들었다.
값을 title, author에서 author를 누락하고 보내면 스브링 부트에서는 해당 필드 null 값으로 처리한다.
** 24/11/06일 수정 : 숫자는 스프링부트에서 해당 필드 값이 누락될 경우 null 아닌 0이다.
** 실제 값을 입력하지 않으면 위와 같이 Json 형태에서 입력하지 않은 값은 누락되어 보내진다.
if (blogDTO.getAuthor() != null || !blogDTO.getAuthor().equals("")) {
// 코드 실행
}
if (blogDTO.getAuthor() != null && !blogDTO.getAuthor().equals("")) {
// 코드 실행
}
누락 값을 입력 받았을 때 backend에서 문제가 될 수 있는 코드이다. 둘 중 하나는 잘못된 코드이다. author가 null일 경우 해당 코드가 실행되지 않도록 하고 싶었다. 즉, 값이 null일 때 if문이 실행되지 않아야 하는데, 처음에는 or 연산자('||')를 사용하여 작성해서 에러가 발생했다. 결론은 or 연산자 대신 and 연산자('&&')를 사용해야 한다.
또한, 이 코드의 의도는 프론트엔드에서 빈 칸이 입력되었을 때도 코드가 실행되지 않도록 하는 것이다.
2. 문제 원인
if (blogDTO.getAuthor() != null || !blogDTO.getAuthor().equals("")) {
// 이 코드에서 NullPointerException 발생 가능
}
getAuthor를 입력받지 않았을 때 if문 안의 코드를 실행하지 못하도록 위와 같이 작성했다. 그런데 현재 코드에서는 if문에서 or 연산자인 '||'를 사용하면 NullPointerException 에러가 발생한다.
** NullPointerException는 참조되지 않은 객체를 이용하려할 때 발생하는 에러이다. C언어에서 포인터를 배우는데 많이 발생하는 에러이다. 쉽게 설명하자면 null은 값이 아니다. 없는 값을 공백으로 표현할 수 없어 null로 키워드가 정의되어 있는 것이지 null이라는 값이 있다는 말이 아니다.
실제로 NullPointerException 에러가 발생하는 것을 확인할 수 있다.
3. 문제 해결 방법
if (blogDTO.getAuthor() != null || !blogDTO.getAuthor().equals("")) {
// 이 코드에서 NullPointerException 발생 가능
}
blogDTO.getAuthor()이 null일 때, 조건문을 살펴보면
- 첫 번째 조건: blogDTO.getAuthor() != null
- 만약 getAuthor()가 null이라면, 이 조건은 false이다.
- 두 번째 조건: ! blogDTO.getAuthor() .equals("")
- 문제 발생: or는 둘 중 하나만 만족하면 되므로 두 번째 조건이 참인지 확인한다. getAuthor() 가 null이므로, null.equals("")를 호출하면 NullPointerException이 발생한다. 즉, null 객체에서는 .equals() 메서드를 사용할 수 없다.
즉, 둘 중 하나만 만족하면 되므로 앞 조건을 시도하고 빠져나와야 하는데 뒤 조건까지 판별하려고 한다. 따라서 null에 equls() 메서드를 사용해서 NullPointerException 에러가 발생한 것이다.
따라서 or 연산자 '||'가 아니라 and 연산자 '&&'를 사용해야 한다.
if (blogDTO.getAuthor() != null && !blogDTO.getAuthor().equals("")) {
// 이 코드가 맞다
}
- 첫 번째 조건: blogDTO.getAuthor() != null
- blogDTO.getAuthor() != null 이 false라면 if문 탈출한다. 따라서 ! blogDTO.getAuthor() .equals("") 는 실행 되지도 않는다. 이렇게 해서 NullPointerException을 방지할 수 있다.
- 두 번째 조건: ! blogDTO.getAuthor() .equals("")
- 실행 안함!!
?. null이 아니라 빈칸을 입력받으면 어떻게 될까?
빈칸("") 일 때, null 체크를 먼저하고 그 다음에 .equals("") 메서드를 호출할 수 있다. 두 번째 조건, ! blogDTO.getAuthor() .equals("")은 flase이므로 빈칸을 입력하면 해당 if문이 실행되지 않는다.
사소한 연산자 차이로 인해 에러가 발생할 수 있다. 또한, null 값은 의도하지 않은 값으로, 사용자가 입력하지 않았을 때 발생할 수 있는 에러이다. 코드를 작성할 때 이러한 요소들을 확실히 이해하고 작성해야 한다.
[결론] : 모르면 외워