오늘은 우리를 괴롭히는 null
에 대해서 어떤식으로 처리할 수 있는지 알아봅시다!
프로젝트를 하던 도중, Optional 이라는 친구를 만났습니다.
java.util.Optional<T>
패키지에 포함되어 있습니다 ㅎㅎ
null이 될 수도 있는 객체
을 감싸고 있는 일종의 래퍼 클래스
입니다.
직접 다루기에 위험하고 까다로운 null을 담을 수 있는 특수한 그릇으로 생각하시면 이해가 쉬우실 것 같습니다.
래퍼 클래스
기본 데이터 옵셔널로 따지면 null 이 들어올 수도 있기 때문에 그 값을 처리하기 위해서 객체를 래퍼 클래스로 감쌌습니다!
1. NullPpintException를 유발할 수 있는 null을 직접 다루지 않아도 됩니다.
2. 수고롭게 null 체크를 직접 하지 않아도 됩니다.
3. n불필요한 방어 로직을 줄일 수 있습니다.
Optional은 제네릭을 제공하기 때문에 변수를 선언할 때 넘어오는 파라미터의 타입에 따라
객체 타입이 설정됩니다. 우리는 User 가 되겠죠!
Optional<User> user; // User 타입의 객체를 감쌀 수 있는 Optional 타입의 변수
Optional<Comment> comment;
Optional<Post> post;
1) Optional.empty()
null을 담고있는 빈 객체를 가져옵니다.
2) Optional.of(value)
null 이 아닌 값을 가지고 있는 객체를 가져옵니다. null 이 넘어오면 오류가 발생합니다.
Optional.ofNullable(value)
객체를 생성했으면, 사용하는 방법도 알아봅시다. Optional 객체에 접근하기 위해선,ㄴ
4가지 방법이 있습니다.
1) get()
Optional 객체를 가져옵니다. 비어있으면 NoSuchElementException을 던집니다.
2) orElse( 인자 값)
Optional 객체를 가져옵니다. 비어있으면 인자 값을 반환합니다.
orElseGet(Supplier<? extends T> other)
orElseThrow(Supplier<? extends X> exceptionSupplier)
Optional 값에서 get()을 호출했는데, 값이 null 인 경우 예외가 발생한다고 말씀 드렸죠? 이런 부분은 null 인지 아닌지 한번 검증을 하면 오류를 예방할 수 있습니다.
isPresent()
를 사용하면 값이 있는지 없는지 확인 할 수 있습니다.
ifPresent()
위에 값과 혼동할 수도 있습니다. 이 메소드는 특정 결과를 반환하는 대신에 Optional 객체가 감싸고 있는 값이 존재할 경우에만 실행될 로직을 함수형 인자로 넘길 수 있습니다.
직접 user 객체를 만들어서 간단한 컴포넌트를 구성해보자
1) 사용할 객체 만들기
public class User {
private Long id;
private String email;
private String password;
2) 사용할 레포지토리 만들기 (JPA 사용함)
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail (String email);
Optional<User> findByName (String name);
}
3) 사용할 서비스 만들기
public class UserService {
private final UserRepository userRepository;
private final JwtTokenProvider jwtTokenProvider;
public void update(Long id, User user) {
User findUser = userRepository.findById(id).orElseThrow(() ->
new IllegalArgumentException("해당 user 가 존재하지 않습니다. id=" + id));
findUser.update(user);
}
}
위에서 주의할 점은 get 으로만 호출해서 값을 가져오면 에러가 날 수 있다는 점이다
항상 골치아팠던 null 처리를 해결할 수 있는 방법을 찾은 것 같아 기쁘고, 아직 익숙하진 않지만 앞으로 할 플젝에서 적용해보고 찾아보고 해야겠다.