Optional은 시작하면 자바 8부터 지원하기 시작했다.
처음은에는 없었다가 생겼다는 것은 무언가 불편한 걸 해결해주기 위해서 등장했을 것이다.
요녀석은 주로 NPE(NullPointException) 발생 방지를 위해 사용한다.
다른 언어에서는 잘 모르겠지만, 특히 객체지향 세상에서 Null
은 쉽게 오류를 발생한다.
메서드가 반환할 값이 없음
을 명백하게 표현할 필요가 있고, null을 반환하면 에러를 유발할 가능성이 높은 상황에서 메서드의 반환 타입으로 Optional
을 사용하자는 것이 Optional
을 사용하는 주 목적
return Null 을 대체하고자 Optional이 등장했다.
반환해주는 메서드에서 Null을 반환하는 것을 대체해준다면 받는 입장에서는
NPE를 걱정하지 않고 코드를 작성할 수 있다.
isPresent()
랑 콤보로 자주 사용하여 예외 처리하는데 개인적으로 아래 더 좋은 메서드가 있다고 생각한다.orElseGet()
의 경우는 예외 객체를 만들어서 처리하는 것보다는 Null 인경우이뿐만 아니라 더 많은 메소드들이 존재한다.
하지만 주로 orElseThrow() 를 사용하고 비슷한 듯 다른 orElseGet() 을 정리해보았다.
💡 함수형 메소드?
주로 옵셔널에서는 아래와 같은 함수형 메소드가 사용된다.
::new
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
여기서 이문법이 잘 이해가 안된다.
하나씩 뜯어보자
<X extends Throwable>
: 제네릭 타입 매개변수를 정의하는 부분으로, X가 Throwable 클래스 또는 그 서브클래스여야 함을 의미한다.T
: 반환 값은 제네릭 타입으로 지정해서 유연하게 객체를 반환한다.orElseThrow
: 메서드명Supplier
: 서플라이어는 @FunctionalInterface
어노테이션을 가지고 있는 인터페이스다.?
: 제네릭의 와일드카드로 , 기본 제네릭과는 다르게 extends,super를 사용하여 타입의 상속관계를 명시적으로 정의하여 유연하게 사용가능하다.<? extends X>
최대 상위 모델이 X를 넘을 수 없다는 뜻으로 예를 들어 NoSuchElementException
을 X 자리에 둔다면 ? 에 사용되는 객체는 NoSuchElementException
이거나 하위타입의 객체여야한다.보통 Repository를 옵셔널로 처리해서하는데 Service에서도 할 수 있고 Controller에서도 가능한데
왜 레포지토리에서 하는게 좋을까?
최초에 객체가 Null임을 알 수 있는 영역은 레포지토리이다.
여기서 처리하지 않고 Service , Controller 둘 중 하나에 처리한다면 사용할 수 없는 데이터를 가지고
이동하느 시간을 갖기 때문에 최대한 빨리 처리하기위해 최초에 처리하는게 좋다.
그리고 DB 데이터의 조회 값이 Null인 경우 이 데이테가 있는지 없는지는 데이터를 관리하는 클래스 레포지토리 책임이 아닐까?
사실 Optional이 없더라도 null 타입을 잘 처리할 수 있다.
그리고 Optional을 모르는 개발자가 봤을 때 이게 클린코드일 수 있을까?
라는 의문도 들긴했다. 하지만 모르더라도 코드가 짧아지고 메서드명에서 쉽게 유추하고
납득할 수 있다는 장점이 있다고 생각한다.
또한 JPA를 사용할 때 편리할 것 같다.
JPA 는 없는 값을 조회할 때 자바 세상에서는 Null을 반환해야 하는데 이때 Optional로 내가 Repository에서 처리해주면 받는 Service단에서는 비즈니스 로직만 수행한다면 편리하지 않을까? 라는 생각도 들었다.
(사실 if문으로 null처리도 가능하긴 하다.)