[자바] NullPointerException 처리 방법

June·2021년 8월 12일
2

NullPointerException

NullPointerException은 실제 값이 아닌 null을 가지고 있는 객체/변수를 호출할 때 발생하는 예외다.

String str = null;
System.out.println(str.toString());

이럴 때 예외가 발생하는게 null에는 toString이 없기 때문이다. 문제는 프로그래밍을 하다보면 해당 변수에 null이 들어있는지, 아닌지를 구분하기가 어렵다는 점이다. 그래서 NullPointerException 처리 방법으로 크게 세 가지가 있다.

Try-Catch

String s = null;
 
try {
    s = s.toUpperCase(); //s를 대문자로 바꾸면서 NullPointerException 발생
    System.out.println(s); //실행되지 않는다.
} catch(NullPointerException e){
    s = "empty";
    System.out.println(s.toUpperCase()); //catch문에서 대문자로 바꾸어준다.
}finally{
    System.out.println("무조건 실행됩니다.");
}

출처: https://dololak.tistory.com/57 [코끼리를 냉장고에 넣는 방법]

하지만 이렇게 변수를 사용할 때마다 try-catch를 섞으면 코드의 양이 어마어마해질 것이고, try-catch는 좋지 않다. 이유는 성공 로직과 실패로직이 뒤섞여 있기 때문이다.

if (variable != null)

public String getCityOfMemberFromOrder(Order order) {
	if (order != null) {
		Member member = order.getMember();
		if (member != null) {
			Address address = member.getAddress();
			if (address != null) {
				String city = address.getCity();
				if (city != null) {
					return city;
				}
			}
		}
	}
	return "Seoul"; // default
}

객체 안의 객체가 있는 구조에서는 이렇게 끔찍한 상황이 온다. 이것 역시 좋지 않아 보인다.

Optional

Optional 자바의 정석 정리

그래서 나온 자바8부터 Optional을 사용한다.

Optional는 “존재할 수도 있지만 안 할 수도 있는 객체”, 즉, “null이 될 수도 있는 객체”을 감싸고 있는 일종의 래퍼 클래스이다.

Optional에서 얻는 장점

  • NPE를 유발할 수 있는 null을 직접 다루지 않아도 된다
  • 수고롭게 null 체크를 직접 하지 않아도 된다
  • 명시적으로 해당 변수가 null일 수도 있다는 가능성을 표현할 수 있다. (따라서 불필요한 방어 로직을 줄일 수 있다.)

Optional 기본 사용법
Optional 의 static method 인 empty(), of(), ofNullable() 을 통해서만 Optional 객체를 생성할 수 있다.

참조변수의 값이 null일 가능성이 있으면, of() 대신 ofNullable()을 사용해야한다. of()는 매개변수의 값이 null이면 NullPointerException이 발생하기 때문이다.

Optional<String> optVal = Optional.of(null); //NPE 발생
Optional<String> optVal = Optional.ofNullable(null); // OK

Optional<T>타입의 참조변수를 기본값으로 초기화할 때는 empty()를 사용한다. null로 초기화하는 것도 가능하지만, empty()로 초기화하는 것이 바람직하다.

Optional<String> optVal = null ;
Optional<String> optVal = Optional.<String>empty(); // 빈 객체로 초기화

Optional 객체의 값 가져오기

Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); //optVal에 저장된 값을 반환. null이면 예외 발생
String str2 = optVal.orElse(""); //optVal에 저장된 값이 null일 때는 ""를 반환

만약 Optional 없이 쓰면 코드를 아래와 같이 쓸 것이다.

SoundCard soundcard = ...;
if(soundcard != null){
  System.out.println(soundcard);
}

Optional을 쓰면 아래와 같이 수정할 수 있다.

Optional<Soundcard> soundcard = ...;
soundcard.ifPresent(System.out::println);

하지만 그렇다면 null check를 할 때

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

이렇게되는데 기존의 if와 크게 차이가 나지 않아 보인다.

Optional<Soundcard> maybeSoundcard = Optional.ofNullable(someSoundcard);
Soundcard soundcard = maybeSoundcard.orElse(new Soundcard("default"));

https://www.daleseo.com/java8-optional-after/
https://www.daleseo.com/java8-optional-effective/
https://jinopia.tistory.com/1

0개의 댓글