본문 바로가기
언어/JAVA

[JAVA] Optional의 사용법 (1/2)

by steadyMan 2022. 7. 25.

코드 작성할 때 흔히 만날 수 있는 예외 중 NullPointerException가 있다. 예외 방지를 위해 조건문을 사용하고 예외를 발생시키는

등의 처리를 하지만 처리를 잊을수 있고 null을 리턴한다는 사실이 문제가 된다. 자바 8에서 null일 가능성이 있는 데이터를 감싸는 Wrapper 클래스인 Optional을 제공한다. 이를 사용해 클라이언트에게 반환 값이 '없음'을 명백하게 표현이 가능하다.

Optional 생성

Opional 클래스는 간편하게 객체 생성을 하도록 3가지의 정적 팩토리 메소드를 제공합니다.

Optional.of()

데이터가 null이 아닐때 사용 가능하다 만약 null일 경우 NullPointerException이 발생한다. 

public Optional<String> getNickName() {
	return Optional.of(nickName);
}

Optional.ofNullable()

데이터가 null일 가능성이 있을때 사용한다. 

public Optional<String> getNickName() {
	return Optional.ofNullable(nickName);
}

Optional.Empty()

null을 담고있는 빈 Optional 객체를 리턴합니다. Optional 내부적으로 미리 생성해놓은 싱글턴 인스턴스가 리턴됩니다. 

public Optional<String> getNickName() {
	return Optional.empty();
}

Optional에 담길 데이터가 int, long, double이라면 

Boxing/UnBoxing의 발생을 예방하기 위해 OptionalInt, OptionalLong, OptionalDouble을 사용하자

OptionalInt opInt = OptionalInt.of(30);
OptionalDouble opDouble = OptionalDouble.of(3.14);
OptionalLong opLong = OptionalLong.of(1000000000);

Optional 데이터 접근 

Optional로 감싸여 있는 객체를 꺼내기 위해 다양한 메소드를 제공합니다. 메소드들은 데이터가 있을 경우 해당 데이터를 리턴하고 null일 경우 다르게 작동합니다. 

.get()

Optional 객체가 비어있을 경우 NoSuchElementException이 발생됩니다.

Optional<User> user = users.stream().filter(us -> us.getNickName().equals("nickName3")).findFirst();
User userObject = user.get();

.orElse(T other)

Optional 객체가 비어있을 경우 파라미터로 받은 객체를 리턴합니다 orElse는 null인지 여부와 무관하게

파라미터의 반환 값을 생성하기 때문에 주의가 필요하다. 

User userObject = user.orElseGet(createNewUser());

.orElseGet(Supplier<? extends T> supplier)

orElse와 유사하지만 null일 경우만 호출되기 때문에 효율성에서 이점이 있습니다. 

User userObject = user.orElseGet(createNewUser());

.orElse() VS .orElseGet()

두개의 메소드는 동일하게 null 값일때 실행되지만 큰 차이점이 있는데 orElse는 null의 여부와 무관하게 일단

createNewUser()가 실행된다. null이 아닐경우에는 불필요한 리소스를 사용하게 되며 null일 경우를 생각하고 작성한 메소드라면 오류상황이 발생할 가능성이있다. 반면 orElseGet()은 null일 경우에만 실행되기 때문에 상황에 맞게 사용할 필요가있다. 

만약 인스턴스가 이미 생성되어있는 경우라면 orElse을 선택해도 무방하다 생각된다. 

.orElseThrow(Supplier<? extends X> exceptionSupplier)

Optional 객체가 비어있을 경우 파라미터로 전달받은 예외를 던집니다. 

User userObject = user.orElseThrow(() -> {
    return new IllegalArgumentException();
});

Filter(), map()

Optional은 Filter(), map()을 제공하는데 해당 메소드를 활용하여 데이터를 유동적으로 접근할 수 있다. 

map()

Optional에 들어있는 값을 변환하여 사용 가능하다. 

/** User의 nickName정보를 리턴한다. null일경우 unknown 리턴 */
public String getUserNickName(User user) {
    return Optional.ofNullable(user).map(User::getNickName).orElse("unknown"); 
}

Filter()

Optional에 들어있는 값을 특정 조건으로 걸러 사용 가능하다. Optional을 반환하여 null의 가능성을 명시한다.

public Optional<User> getUserNickName(User user) {
    return Optional.ofNullable(user).filter(us -> us.getAge() > 100);
}

댓글