[java] Java 8의 Optional.ifPresent 및 if-not-present의 기능적 스타일?

Java 8에서는 Optional객체가 있으면 객체에 무언가를 하고 싶지 않으면 다른 일을 하고 싶습니다 .

if (opt.isPresent()) {
  System.out.println("found");
} else {
  System.out.println("Not found");
}

그러나 이것은 ‘기능적 스타일’이 아닙니다.

OptionalifPresent()방법을하지만, 나는 체인 드릴 수 없습니다 orElse()방법.

따라서 나는 쓸 수 없다 :

opt.ifPresent( x -> System.out.println("found " + x))
   .orElse( System.out.println("NOT FOUND"));

@assylias에 대한 답변으로 Optional.map()다음과 같은 경우에는 효과 가 없다고 생각 합니다.

opt.map( o -> {
  System.out.println("while opt is present...");
  o.setProperty(xxx);
  dao.update(o);
  return null;
}).orElseGet( () -> {
  System.out.println("create new obj");
  dao.save(new obj);
  return null;
});

이 경우 opt존재하는 경우 속성을 업데이트하고 데이터베이스에 저장합니다. 사용할 수 없으면 새로 작성 obj하여 데이터베이스에 저장합니다.

두 개의 람다에 주목해야한다 null.

그러나 opt존재하는 경우 두 람다가 모두 실행됩니다. obj업데이트되고 새 개체가 데이터베이스에 저장됩니다. 이것은 return null첫 번째 람다 때문입니다 . 그리고 orElseGet()계속 실행될 것입니다.



답변

저에게 @Dane White의 대답은 괜찮습니다. 먼저 Runnable을 사용하는 것을 좋아하지 않았지만 대안을 찾을 수 없었습니다. 여기에서 선호하는 다른 구현

public class OptionalConsumer<T> {
    private Optional<T> optional;

    private OptionalConsumer(Optional<T> optional) {
        this.optional = optional;
    }

    public static <T> OptionalConsumer<T> of(Optional<T> optional) {
        return new OptionalConsumer<>(optional);
    }

    public OptionalConsumer<T> ifPresent(Consumer<T> c) {
        optional.ifPresent(c);
        return this;
    }

    public OptionalConsumer<T> ifNotPresent(Runnable r) {
        if (!optional.isPresent()) {
            r.run();
        }
        return this;
    }
}

그런 다음 :

Optional<Any> o = Optional.of(...);
OptionalConsumer.of(o).ifPresent(s ->System.out.println("isPresent "+s))
            .ifNotPresent(() -> System.out.println("! isPresent"));

업데이트 1 :

가치가 있고 그것을 처리하고 싶을 때 전통적인 개발 방식에 대한 위의 솔루션이지만 기능을 정의하고 실행하려면 다음 개선 사항을 확인하십시오.

public class OptionalConsumer<T> implements Consumer<Optional<T>> {
private final Consumer<T> c;
private final Runnable r;

public OptionalConsumer(Consumer<T> c, Runnable r) {
    super();
    this.c = c;
    this.r = r;
}

public static <T> OptionalConsumer<T> of(Consumer<T> c, Runnable r) {
    return new OptionalConsumer(c, r);
}

@Override
public void accept(Optional<T> t) {
    if (t.isPresent()) {
        c.accept(t.get());
    }
    else {
        r.run();
    }
}

그런 다음 다음과 같이 사용할 수 있습니다.

    Consumer<Optional<Integer>> c=OptionalConsumer.of(System.out::println, ()->{System.out.println("Not fit");});
    IntStream.range(0, 100).boxed().map(i->Optional.of(i).filter(j->j%2==0)).forEach(c);

이 새로운 코드에는 3 가지가 있습니다.

  1. 기존 객체를 쉽게 사용하기 전에 기능을 정의 할 수 있습니다.
  2. 각 옵션에 대해 객체 굴절을 생성하지 않음 선택 사항, 하나만, 메모리가 적고 GC가 적습니다.
  3. 다른 구성 요소와의 더 나은 사용을 위해 소비자를 구현하고 있습니다.

그건 그렇고 지금은 그 이름이 더 묘사 적입니다. 실제로 소비자입니다.>


답변

Java 9 이상을 사용하는 경우 다음 ifPresentOrElse()방법 을 사용할 수 있습니다 .

opt.ifPresentOrElse(
   value -> System.out.println("Found: " + value),
   () -> System.out.println("Not found")
);


답변

자바 9 소개

ifPresentOrElse 값이 있으면 값으로 지정된 조치를 수행하고, 그렇지 않으면 주어진 빈 기반 조치를 수행합니다.

Java 8 치트 시트의 탁월한 Optional을 참조하십시오 .

대부분의 사용 사례에 대한 모든 답변을 제공합니다.

아래 요약

ifPresent ()-Optional이 설정되면 무언가를한다

opt.ifPresent(x -> print(x));
opt.ifPresent(this::print);

filter ()-특정 선택적 값을 거부 (필터 아웃)합니다.

opt.filter(x -> x.contains("ab")).ifPresent(this::print);

map ()-존재하는 경우 값을 변환

opt.map(String::trim).filter(t -> t.length() > 1).ifPresent(this::print);

orElse () / orElseGet () – 비어 있음

int len = opt.map(String::length).orElse(-1);
int len = opt.
    map(String::length).
    orElseGet(() -> slowDefault());     //orElseGet(this::slowDefault)

orElseThrow ()-비어있는 경우 예외적으로 예외 처리

opt.
filter(s -> !s.isEmpty()).
map(s -> s.charAt(0)).
orElseThrow(IllegalArgumentException::new);


답변

대안은 다음과 같습니다.

System.out.println(opt.map(o -> "Found")
                      .orElse("Not found"));

그래도 가독성이 향상되지는 않는다고 생각합니다.

또는 Marko가 제안한 것처럼 삼항 연산자를 사용하십시오.

System.out.println(opt.isPresent() ? "Found" : "Not found");


답변

또 다른 해결책은 다음과 같이 고차 함수를 사용하는 것입니다.

opt.<Runnable>map(value -> () -> System.out.println("Found " + value))
   .orElse(() -> System.out.println("Not Found"))
   .run();


답변

즉시 사용할 수있는 좋은 방법은 없습니다. 클리너 구문을 정기적으로 사용하려면 다음과 같은 유틸리티 클래스를 작성할 수 있습니다.

public class OptionalEx {
    private boolean isPresent;

    private OptionalEx(boolean isPresent) {
        this.isPresent = isPresent;
    }

    public void orElse(Runnable runner) {
        if (!isPresent) {
            runner.run();
        }
    }

    public static <T> OptionalEx ifPresent(Optional<T> opt, Consumer<? super T> consumer) {
        if (opt.isPresent()) {
            consumer.accept(opt.get());
            return new OptionalEx(true);
        }
        return new OptionalEx(false);
    }
}

그런 다음 다른 곳에서 정적 가져 오기를 사용하여 다음에 가까운 구문을 얻을 수 있습니다.

import static com.example.OptionalEx.ifPresent;

ifPresent(opt, x -> System.out.println("found " + x))
    .orElse(() -> System.out.println("NOT FOUND"));


답변

Java 8 이하 만 사용할 수있는 경우 :

1) spring-data지금까지 가장 좋은 방법 이 없다면 :

opt.<Runnable>map(param -> () -> System.out.println(param))
      .orElse(() -> System.out.println("no-param-specified"))
      .run();

이제는 읽기가 어렵고 이해하기가 어렵다는 것을 알고 있지만 개인적으로 나에게 잘 어울리 며이 경우에는 유창한 또 다른 유창한 방법을 보지 못합니다.

2) 당신이 충분히 운 spring-data이 좋으며 가장 좋은 방법을
사용할 수 있다면 Optionals #ifPresentOrElse입니다 .

Optionals.ifPresentOrElse(opt, System.out::println,
      () -> System.out.println("no-param-specified"));

Java 9를 사용할 수 있다면 반드시 다음을 수행해야합니다.

opt.ifPresentOrElse(System.out::println,
      () -> System.out.println("no-param-specified"));