1.NULL 이란?
NULL은 값이 없음을 나타내는 문자이다. (참조가 아무 객체도 가리키고 있지 않다.)
사실 맨 처음 프로그래밍을 배울때 NULL의 개념에 대해 들으면, 이게 뭔지 햇갈릴수 있다.
여기 간단한 예시용 사람 클래스가 있다.
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void sayHello() {
System.out.println("안녕하세요! 제 이름은 " + name + "입니다.");
}
}
그리고 이제 사람들의 리스트를 가지고있고, 이름을 통해 사람을 반환해주는 메서드를 추가할것이다.
public class PersonManager { //이름으로 사람을 찾아줘요~
private List<Person> people;
public PersonManager(){
Person person = new Person("홍길동");
Person person2 = new Person("김철수");
people = List.of(person, person2);
}
}
단순히 생각하면 그냥 사람 리스트에서 이렇게 equals로 이름이 같은 사람을 찾아서 반환해주는 코드로 끝날거같지만, 아래 코드에서 만약 이름이 같은 사람이 없다면? 반환이 아에 안되는걸까?
public Person getPersonByName(String name) {
for (Person person : people) { //이름이 같은 사람을 반환해줌
if (person.getName().equals(name)) {
return person;
}
}
}
이때 아무것도 반환하지않는것은 불가능하니까 Person 객체 대신 아무값이 없다는것을 나타내기 위한 null 반환을 사용할수있는거다.
public Person getPersonByName(String name) {
for (Person person : people) {
if (person.getName().equals(name)) {
return person;
}
}
return null; //이름이 같은사람이없네;;;;
}
2.NPE(Null Pointer Exception)의 시작
자 이제 만들었으니까 사용해보면? 코드에러도 안뜨고 잘 사용이 된다!
PersonManager manager = new PersonManager();
Person person = manager.getPersonByName("홍길동");
person.sayHello();
안녕하세요! 제 이름은 홍길동입니다.
근데 여기서 만약 존재하지않는 이름의 사람을 찾아서 null이 반환된다면..?
PersonManager manager = new PersonManager();
Person person = manager.getPersonByName("고구미"); //없는 이름 고구미를 찾아줘
person.sayHello();
Null Pointer Exception이 발생하게 된다...
이유는 null은 실제 Person의 인스턴스가 아니라 아무 객체도 가리키고 있지 않다는 뜻이기 떄문에 .sayHello() 메서드를 실행할 수 없기 때문이다...
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Person.sayHello()" because "person" is null
at Main.main(Main.java:5)
그래서 코드 오류는 없지만 person 변수가 null일때를 따로 체크해주지않는다면, null이 올때 원치않은 런타임 에러를 겪게 될것이다..
PersonManager manager = new PersonManager();
Person person = manager.getPersonByName("고구미");
if (person == null) { //null 일때를 별도로 처리해줘야해
System.out.println("해당 이름을 가진 사람이 없습니다.");
return;
}
person.sayHello();
해당 이름을 가진 사람이 없습니다.
3. NULL 반환의 문제
3.1 실수 유발
위에서 본것처럼 Null Pointer Exception을 유발하는 코드였지만, null이 실제로 반환되어 에러를 겪기 전까지는 에러인것을 인지하지 못할 수 있다. 익숙해진다면 해당 코드마다 개발자가 null일때의 처리를 해줄 수 있겠지만 이렇게 개발자에게 의존하여 처리하는것은 좋지 않아 보인다.
if (person == null) { //null 일때를 별도로 처리해줘야해
System.out.println("해당 이름을 가진 사람이 없습니다.");
return;
}
3.2 호출자측 책임 전가 및
두번째는 호출자측한테 NULL 체크 책임을 넘겨준다는것이다.
나는 분명 "Person 반환타입의 메서드에 사람을 찾아주세요~"를 호출했는데 사람이 아닌 NULL 이라는 이상한 값이 오고, 이걸 또 내가 직접 별도로 확인해 줘야한다는것이다.
3.3. NULL의 의도 불명?
그리고 NULL 반환을 남용하면 다음 코드같은 상황이 일어날수도있다. 에초에 Person 리스트가 없으니까 찾은 사람도 없으니 NULL이 반환된건지, 이름이 일치한 사람이 없어서 NULL이 반환된건지 알수가 없다.
public Person getPersonByName(String name) {
if (people == null) {
return null; // 리스트가 없음
}
for (Person person : people) {
if (person.getName().equals(name)) {
return person; // 찾았음
}
}
if (!people.isEmpty()) {
return null; // 이름 일치하는 사람 없음
}
if (people.isEmpty()) {
return null; // 사람자체가 없음
}
return null; // 아무튼 없음;
}
4. NULL 반환의 해결법
4.1 Optional
이런 NULL 반환을 대체할만한걸로 우선 Java 8부터 도입된 래퍼클래스인 Optinal이 있다.
반환 타입에 Optinal을 씌우게 되면 NULL 대신 Optional.empty()를 반환할수 있게된다.
public Optional<Person> getPersonByName(String name) {
for (Person person : people) {
if (person.getName().equals(name)) {
return Optional.of(person);
}
}
return Optional.empty();
}
그러면 당연히 타입을 바꿨으니 기존 코드에서는 다음 오류가 발생한다.

Type mismatch: cannot convert from Optional<Person> to Person
때문에 개발자는 값이 존재하면 그 값을 반환하고, 없으면 예외를 던지는 기능을 수행하는 .orElseThrow를 체이닝으로 강제로 달게 된다. 이를 통해 개발자가 빈값 체크를 잊을일은 거의없다고 볼 수 있다.
Person person = manager.getPersonByName("고구미")
.orElseThrow(() -> new Exception("사람을 못찾겠는데요?"));
4-2.Null Object 패턴
Null Object 패턴은 NULL 대신 쓸수있는 객체를 미리 만들어두는거다. 이떄 내부 동작은 작동하지않게 빈 메서드로 둔다.
이 패턴작성의 장점은 반복문같은 경우에서 오류없는 작동을 기대할수 있다는것이다.
public class NullPerson extends Person {
public NullPerson() {
super("");
}
@Override
public void sayHello() {
}
}
아래 반복문에서 NullPerson인 경우에는 아무동작도 하지않기 때문에, 존재하는 Person에 대해서만 sayHello 메서드 값을 기대할수있을것이다.
for (String name : namesToFind) {
Person person = service.getPersonByName(name);
person.sayHello(); // NullPerson이면 아무 일도 일어나지 않음
}
4-3. 그냥 예외처리하기
NULL을 호출자한테 반환하고 예외처리하지 말고, 그냥 NULL을 반환하는 대신 호출되는 함수쪽에서 예외를 처리하는 방법이다.
이경우에는 호출자는 NULL 확인하는 책임을 전가받지도않고, NULL오류를 방지할 수 있다.
public Person getPersonByName(String name) {
for (Person person : people) {
if (person.getName().equals(name)) {
return person;
}
}
throw new IllegalArgumentException("사람을 못찾겠는데요?");
}
5.RestAPI에서의 NULL
다음은 OK(200, 성공) 이지만 null을 반환하고 있는 상황이다.
이 경우에도 클라이언트는 분명 200 상태코드를 받았는데도 NULL 체크를 별도로 수행해야할 필요가 있을것이다..
return ResponseEntity.ok().body(null);
이때는 null을 body로 반환하는 대신, 204(No Content) 상태 코드와 함께 body가 없다는것을 나타내며 반환하는것이 더 올바른 선택일수 있다. (클라이언트가 200 상태일때는 null인 경우를 고려안해도된다.)
return ResponseEntity.noContent().build();
6. NULL은 반환하면 안되는 걸까?
Why is using an optional preferential to null-checking the variable?
Take the two code examples: if(optional.isPresent()) { //do your thing } if(variable != null) { //do your thing } As far as I can tell the most obvious difference is that the Optional req...
softwareengineering.stackexchange.com
나는 이글을 특히 인상깊게 읽었다.
"Without Optional, every reference in your code is like an unexploded bomb"
Optional을 사용하지않는 모든 참조 코드는 터지지않은 폭탄이라는 것이다.
SpringBoot 프레임워크와 같은 경우 Optional을 지원하지않는 자바버전을 커버하기 위해 null을 반환하는 것으로 보이지만,
지금 Optional이 존재하는 Java 버전을 사용하는 경우 굳이 이런 위험을 감수하고 NULL 반환을 사용하는 이유가 있을까 하는 생각이다.
'BackEnd > SpringBoot' 카테고리의 다른 글
| 반환코드 204 vs 404 (0) | 2025.09.18 |
|---|---|
| [SpringBoot] FlyWay란?, 사용법 (1) | 2025.09.07 |
| [SpringBoot] @Mock 사용법 (0) | 2025.09.03 |