NullPointerException은 실제 값이 아닌 null을 가지고 있는 객체/변수를 호출할 때 발생하는 예외다.
String str = null;
System.out.println(str.toString());
이럴 때 예외가 발생하는게 null에는 toString이 없기 때문이다. 문제는 프로그래밍을 하다보면 해당 변수에 null이 들어있는지, 아닌지를 구분하기가 어렵다는 점이다. 그래서 NullPointerException 처리 방법으로 크게 세 가지가 있다.
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는 좋지 않다. 이유는 성공 로직과 실패로직이 뒤섞여 있기 때문이다.
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
}
객체 안의 객체가 있는 구조에서는 이렇게 끔찍한 상황이 온다. 이것 역시 좋지 않아 보인다.
그래서 나온 자바8부터 Optional을 사용한다.
Optional는 “존재할 수도 있지만 안 할 수도 있는 객체”, 즉, “null이 될 수도 있는 객체”을 감싸고 있는 일종의 래퍼 클래스이다.
Optional에서 얻는 장점
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