자바/함수형 프로그래밍

Optional

끄적끄적 2022. 5. 27. 20:51

Optional 만드는 법
• of – Null이 아닌 오브젝트를 이용해 Optional을 만들 때
empty – 빈 Optional을 만들 때
ofNullable – Null인지 아닌지 알지 못하는 오브젝트로 Optional을 만들 때

private static final Optional<?> EMPTY = new Optional<>(null);

public static <T> Optional<T> of(T value) {
    return new Optional<>(Objects.requireNonNull(value));
}
public static<T> Optional<T> empty() {
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? (Optional<T>) EMPTY
                         : new Optional<>(value);
}

Optional 안에 있는 값을 확인하고 꺼내는 법
• isPresent – 안의 오브젝트가 null인지 아닌지 체크. Null이 아닐 시 true
• get – Optional 안의 값을 추출. Null이라면 에러
orElse – Optional이 null이 아니라면 Optional 안의 값을, null이라면 other로 공급된 값을 리턴
orElseGet – Optional이 null이 아니라면 Optional 안의 값을, null이라면 supplier로 공급되는 값을 리턴
orElseThrow – Optional이 null이 아니라면 Optional 안의 값을, null이라면 exceptionSupplier로 공급되는 exception

public boolean isPresent() {
    return value != null;
}

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
    
public T orElse(T other) {
    return value != null ? value : other;
}   

public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}

public T orElseThrow() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
    
public T orElseThrow() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

사용예

Optional<String> maybeEmail = Optional.of(someEmail);
Optional<String> maybeEmail2 = Optional.empty();
Optional<String> maybeEmail3 = Optional.ofNullable(someEmail);
Optional<String> maybeEmail4 = Optional.ofNullable(nullEmail);

String email = maybeEmail.get();	  
if (maybeEmail2.isPresent()) {
  System.out.println(maybeEmail2.get());
}

String defaultEmail = "default@email.com";
String email3 = maybeEmail2.orElse(defaultEmail);
String email4 = maybeEmail2.orElseGet(() -> defaultEmail);
String email5 = maybeEmail2.orElseThrow(() -> new RuntimeException("email not present"));

Optional 응용을 위해 알아야 할 것들
• ifPresent – Optional이 null이 아니라면 action을 실행
• map – Optional이 null이 아니라면 mapper를 적용
flatMap – mapper의 리턴 값이 또 다른 Optional이라면 한 단계의 Optional이 되도록 납작하게 해줌
            Optional<Optional<T>> --> Optional<T>

public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        @SuppressWarnings("unchecked")
        Optional<U> r = (Optional<U>) mapper.apply(value);
        return Objects.requireNonNull(r);
	}
}

사용예

public static void main(String[] args) {
    Optional<User> maybeUser = Optional.ofNullable(maybeGetUser(true));
    maybeUser.ifPresent(System.out::println);

    Optional<Integer> maybeId = Optional.ofNullable(maybeGetUser(true))
        .map(user -> user.getId());
    maybeId.ifPresent(System.out::println);

    String userName = Optional.ofNullable(maybeGetUser(true))
        .map(User::getName)
        .map(name -> "The name is " + name)
        .orElse("Name is empty");
    System.out.println(userName);

    Optional<String> maybeEmail = Optional.ofNullable(maybeGetUser(true))
        .flatMap(User::getEmailAddress);
    maybeEmail.ifPresent(System.out::println);
}
반응형