Optional이란?
Optional은 자바 8부터 도입된 클래스입니다.
해당 클래스는 어떠한 객체 혹은 어떠한 값의 Null여부를 표현하는 데 사용하기 위한 클래스입니다.
기존에는 다음과 같이 null 여부를 판단해서 처리했다면, Optional을 사용하면 가독성 있게 작업할 수 있습니다.
// 기존 null 처리 방식
if(temp == null) return false;
else return temp;
// Optional 사용 방식
return Optional.ofNullable(temp).orElse(false);
Optional을 사용하면 얻을 수 이점은 다음과 같습니다.
1. null 을 명시적으로 처리할 수 있게 되고 이에 따라서 NullPointerException 때문에 발생하는 실수를 줄일 수 있습니다.
2. 가독성이 눈에띄게 좋아집니다.
3. 함수형 프로그래밍을 사용할 수 있습니다.
Optional에서 제공하는 메서드를 확인해 가면서 알아봅시다.
Optional의 메서드
Optional에서 제공하는 메서드는 종류가 꽤 많은데, 한번 검색해보시는 걸 추천드립니다. 여기서는 몇 가지만 소개해드리겠습니다.
1. 생성 메서드
> Optional.empty()
말 그대로 Optional을 생성하는 메서드입니다. Optional객체를 반환하며 그중에 아무것도 없는, 빈값의 Optional을 생성하는 메서드입니다.
// 비어있는 Optional 객체를 반환
Optional.empty();
> Optional.ofNullable(value)
Optional 객체를 반환합니다.
value 라는 변수가 null 일 수 있을 때 사용합니다. 만약 value가 null이라면 Optional.empty()를 반환합니다.
// value 라는 변수가 null이 올 수도 있음(null 허용)
Optional.ofNullable(value)
> Optional.of(value)
Optional 객체를 반환합니다.
value 가 null이 아니어야 하며 null일 경우 NullPointerException이 발생합니다.
// value가 null일 수 없음(null 허용 안됨)
Optional.of(value)
위의 생성 메서드를 이용해서 Optional을 생성할 수 있습니다.
2. 값을 얻는 메서드
> get()
Optional이 비어있지 않을 때 그 값을 반환합니다. 만약 Optional이 비어있다면(Optional.empty()) NoSuchElemnetException을 반환합니다.
> orElse(value)
Optional이 비어있을 경우 기본값(value)을 반환합니다.
> orElseGet(Supplier<? extends T> other)
Optional이 비어있을 경우 supplier를 통해 제공된 값을 반환합니다.
> orElseThrow(Supplier<? extends X> exceptionSupplier)
Optional이 비어있을 경우 Supplier 를 통해 제공된 예외를 던집니다.
3. 값을 가공하는 매서드
값을 가공하는 메서드는 종류가 많습니다. 그중에서 많이 쓰이는 메서드 몇 가지만 쓰겠습니다.
> map(Function <? supper T,? extends U> mapper)
Optional이 비어있지 않을 때 (Optional.empty()가 아닐 때) 값을 가공하는 map 함수를 적용하여 새로운 Optional을 반환합니다.
> flatMap(Function <? super T, Optional <U>> mapper)
Optional이 비어있지 않을 때, 함수 mapper를 적용해 Optional을 반환합니다.
> filter(Predicate <? super T> predicate)
Optional이 비어 있지 않을 때, predicate 함수를 적용해 새로운 Optional을 반환합니다.
Optional 사용하기
Optional을 사용하기 전에는 다음과 같은 분기문이 있습니다.
String temp = "";
if(value == null){
throw new NullPointerException();
}
else{
temp = value;
}
value라는 변수가 null이면 예외를 반환하고 아니라면 temp에 value를 대입하는 간단한 분기문인데요 이 내용을 한 줄로 처리할 수 있습니다.
String temp = Optional.ofNullable(value).orElseThrow(NullPointerException::new);
많이 간단해진 모습입니다. 하나하나 분석을 해보겠습니다
// null이 올수도 있다
Optional.ofNullable(value)
위 함수를 통해 value 값이 null인지 아닌지 판단합니다. 만약 null이라면 빈 Optional을 반환할 것이고 아니라면 Optional로 감싼 형태의 값을 가지고 있게 됩니다.
Optional.ofNullable(value).orElseThrow(NullPointerException::new);
만약 Null이 아니라면 value 값 그 자체를 반환할 것이고 만약 Null이라면 빈 Optional을 반환할 것인데 만약 빈 Optional이 온다면 orElseThrow 메서드를 통해 구현한 NullPointException을 던지게 됩니다.
Optional은 어떤 값을 감싼다라고 생각하시면 편합니다. 위에 소개해드린 Optional의 메서드 중 생성메서드와, 가공메서드를 이용하면 Optional 객체로 반환이 되고 반환된 Optional을 반환 메서드를 통해 감싸져 있는 Optional을 벗겨내는 거죠.
이 전에 작성한 게시글에 스트림에 대한 내용이 있는데 이 스트림을 이용하는 방법과 흡사합니다. 값을 얻어오는 가공메서드를 사용하면 리턴되는 값도 Optional이니 계속해서 데이터를 가공할 수 있는 거죠.
혹시 자바의 스트림에 대해서 모르신다면 이 글도 한번 보시는걸 추천드립니다.
스트림이란?
2024.03.25 - [개발/웹 개발] - [JAVA/자바] 스트림(Stream)
Optional의 실제 사용 경험
저를 잠시 생각하게 만들었던 경우를 하나 소개해드리고 마치겠습니다.
다음과 같은 객체가 있다고 가정하겠습니다.
public class Temp{
private String value;
public Temp(String value){
this.value = value;
}
public String getValue(){
return value;
}
이 객체를 반환해야 하는 로직이 하나 있었는데요, 요새 제가 if문을 어떻게 하면 최대한 줄일 수 있을까? 하는 생각에 빠져있던 터라 해당 부분을 Optional을 이용해서 한 줄로 처리하고 싶었습니다.
여러분도 보시고 어떻게 하면 한 번에 처리할 수 있을지 고민해 보세요
public String test(Temp temp){
if(temp == null) return null;
return temp.getValue();
}
여기서 생각해야 하는 요점은 temp객체 자체가 null일수도 있고, getValue를 통해 반환되는 값이 null인 경우도 있습니다. 또한 이 test 메서드는 temp가 null이라면 예외를 던지는 게 아닌, 꼭 null을 반환해야 했습니다.
그래서 Optional안에 또 Optional을 이용해보려 했으나 가능하지 않았습니다.
return Optional.ofNullable(
Optional.ofNullable(temp).orElse(null).getValue()
).orElse(null);
이렇게 하면 되지 않을까라고 생각하는 순간, temp가 null이 아니라면 temp객체를 반환하기에 getValue를 잘 호출하겠다 싶었는데, 실제로 null이라면 orElse 메서드로 해당 값을 null로 세팅하게 되는데 그렇게 되면 null.getValue()가 되어버리기 때문에 NullPointerException이 발생할 수밖에 없다는 생각이 들었습니다.
그래서 고민에 고민을 한 결과 map메서드를 이용해 데이터를 한번 가공해서 처리하게 되었습니다.
// 바꾼 코드
return Optional.ofNullable(temp).map(i -> i.getValue()).orElse(null);
우선 Optional.ofNullable(temp)를 통해 temp가 null이라면 map 메서드를 호출하지 않을 것이니 temp자체가 null인 경우는 해결하였습니다.
만약 null이 아니라면 map 메서드가 실행될 테니 map 메서드를 통해 temp의 getValue 메서드를 호출하게 만들어 데이터를 가공했습니다.
이후 해당 값이 null이 아니라면 getValue를 통해 나온 값이 반환될 것이고 아니라면 orElse(null) 메서드를 통해 null을 반환하게 될 것입니다.
이렇게 Optional에 대해 알아보았습니다. 처음 사용하시는 분들은 많이 어색하시고 어떻게 적용할지 답답하실 수 있는데 역시 사람은 적응의 동물이라고... 사용하다 보면 금방 익숙해지더군요.
혹시 틀린 내용이 있거나 궁금하신 내용은 댓글로 알려주세요. 감사합니다.
'개발 > 웹 개발' 카테고리의 다른 글
[JAVA/자바] 람다(Lambda) (6) | 2024.04.03 |
---|---|
[JAVA/자바] 제네릭(Generic) (0) | 2024.04.01 |
[JAVA/자바]HttpURLConnection 이용한 파일 다운로드 (0) | 2023.02.08 |