흔히 스프링에서 객체에 무언가를 조회한다음 객체 !=null
을 사용해서 데이터가 올바르게 조회되지않음을 나타내곤한다. 이건 좋은 습관일까?
흔히 null은 그냥 "없어요" 라는 느낌으로 알고넘어가는데 조금 더 깊게 설명해보자면
원시타입(primitive type)에서 디폴트값으론 보통 false나 0이 들어간다. 참조타입(reference type)에서도 없다는걸 표현하기 위해 null을 넣은것이다.
int i = null;//안됨
String s = null;//됨
원시 타입 :
boolean
,char
,int
참조 타입 :Integer
,String
, 클래스, array
그럼 왜 null을 방지해야하는가? 그건 NullPointerException(NPE)
을 방지하란 말과 똑같다.
NPE는 위와같은 참조타입을 사용한 부분에서 발생할 수 있는 오류다. 때문에 다양한곳에서 발생할수도있으며 런타임에 발생하기때문에 한번 돌려보지않으면 모른다는것이다.
이를 방지하기위한 방법은 두가지가 있다.
코테문제를 풀때 주로 쓰는 방법이다. 이를 스프링 코드에 적용하자면
private void validateDuplicateMember(Member member){
Member findMember = memberRepository.findByUsername(member.getUsername());
if(findMember != null){
throw new IllegalStateException("이미 존재하는 아이디입니다.");
}
}
findMember는 Member 클래스의 객체이므로 참조타입이다. 때문에 null이 발생할 수 있고 이를 !=null
로 간단하게 처리했다. 물론 간단한코드에서는 이렇게 처리해도되지않나 라는 생각이긴하다. 😅
private void validateMemberAge(Member member){
if (member != null) {
if (member.getAge() >= 18) {
System.out.println("성인 회원입니다.");
} else {
System.out.println("미성년자 회원입니다.");
}
} else {
System.out.println("회원 정보가 없습니다.");
}
}
반면 위처럼 if문이 중첩될 때 위보다 훨씬 많은 if가 중첩되면 중첩될수록 가독성을 헤치게된다. 그럴때에는 Optional
을 사용해서 함수형 스타일의 코드로 작성하면 된다.
JAVA8 기능중 하나인 Wrapper클래스이고 있을수도있지만? 없을수도있는 객체다.
비슷한 Wrapper클래스는
Collection
이랑Stream
과같은애들이 있는데 얘넨 원소가 하나다.
이와같은 특성으로 null이 방지가되는데 그릇은 있으니 그릇 위에 뭐가 없어도 문제는 없다 라는 느낌으로 이해하면될거같다.
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByUsername(String username);
}
우선 JPA를 활용하여 findByUsername메서드를 Optinoal로 반환하도록 한다. 이게 핵심이다. 반환값으로 사용한다는 것!
private void validateDuplicateMember(Member member){
Optional<Member> findMember = memberRepository.findByUsername(member.getUsername());
if(findMember.isPresent()){
throw new IllegalStateException("이미 존재하는 아이디입니다.");
}
}
위의 첫번째 코드에서 optinal로 객체를 감싸고 if부분만 바꾼 예시다. 이렇게하면 뭐가다른거지? 라고하면 맞는말이다. Optinal의 핵심은 함수형 프로그래밍이다. 위처럼 빈 객체에 집어넣지 말자.
private void validateDuplicateMember(Member member){
memberRepository.findByUsername(member.getUsername())
.ifPresent(findMember -> {
throw new IllegalStateException("이미 존재하는 아이디입니다.");
});
}
아래처럼 findByUsername().ifPresent()로 함수형코드형태를 이루어 작성하도록 쓰는게 올바른 쓰임세이다!