在Java 8中,我想对一个可选对象做一些事情,如果它是存在的,并做另一件事,如果它不存在。

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

不过,这不是一种“功能性风格”。

Optional有一个ifPresent()方法,但我无法链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并保存到数据库。

注意,在两个lambda中,我必须返回null。

但是当opt存在时,两个lambdas都将被执行。Obj将被更新,一个新的对象将被保存到数据库中。这是因为在第一个lambda中返回null。orElseGet()将继续执行。


当前回答

另一种选择是:

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

但我不认为它能提高可读性。

或者像Marko建议的那样,使用三元操作符:

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

其他回答

另一个解决方案是:

下面是它的用法:

    final Opt<String> opt = Opt.of("I'm a cool text");
    opt.ifPresent()
        .apply(s -> System.out.printf("Text is: %s\n", s))
        .elseApply(() -> System.out.println("no text available"));

或者如果你。如果相反的用例是真的:

    final Opt<String> opt = Opt.of("This is the text");
    opt.ifNotPresent()
        .apply(() -> System.out.println("Not present"))
        .elseApply(t -> /*do something here*/);

这些是成分:

稍微修改了函数界面,只是为了“elseApply”方法 可选增强 一点点卷曲:-)

“美化”增强的功能界面。

@FunctionalInterface
public interface Fkt<T, R> extends Function<T, R> {

    default R elseApply(final T t) {
        return this.apply(t);
    }

}

和用于增强的Optional包装器类:

public class Opt<T> {

    private final Optional<T> optional;

    private Opt(final Optional<T> theOptional) {
        this.optional = theOptional;
    }
    
    public static <T> Opt<T> of(final T value) {
        return new Opt<>(Optional.of(value));
    }

    public static <T> Opt<T> of(final Optional<T> optional) {
        return new Opt<>(optional);
    }
    
    public static <T> Opt<T> ofNullable(final T value) {
        return new Opt<>(Optional.ofNullable(value));
    }
    
    public static <T> Opt<T> empty() {
        return new Opt<>(Optional.empty());
    }

    private final BiFunction<Consumer<T>, Runnable, Void> ifPresent = (present, notPresent) -> {
        if (this.optional.isPresent()) {
            present.accept(this.optional.get());
        } else {
            notPresent.run();
        }
        return null;
    };

   private final BiFunction<Runnable, Consumer<T>, Void> ifNotPresent = (notPresent, present) -> {
        if (!this.optional.isPresent()) {
            notPresent.run();
        } else {
            present.accept(this.optional.get());
        }
        return null;
    };

    public Fkt<Consumer<T>, Fkt<Runnable, Void>> ifPresent() {
        return Opt.curry(this.ifPresent);
    }

    public Fkt<Runnable, Fkt<Consumer<T>, Void>> ifNotPresent() {
        return Opt.curry(this.ifNotPresent);
    }

    private static <X, Y, Z> Fkt<X, Fkt<Y, Z>> curry(final BiFunction<X, Y, Z> function) {
        return (final X x) -> (final Y y) -> function.apply(x, y);
    }
}

这应该可以解决问题,并且可以作为处理此类需求的基本模板。

The basic idea here is following. In a non functional style programming world you would probably implement a method taking two parameter where the first is a kind of runnable code which should be executed in case the value is available and the other parameter is the runnable code which should be run in case the value is not available. For the sake of better readability, you can use curring to split the function of two parameter in two functions of one parameter each. This is what I basically did here.

提示:Opt还提供了另一个用例,在该用例中,您希望执行一段代码,以防该值不可用。这也可以通过Optional.filter.stuff完成,但我发现这更可读。

希望有帮助!

额外的信息:

还有另一种表达if then else的方法:

public static <X, Y> Function<Predicate<X>, Function<Function<X, Y>, Function<Function<X, Y>, Y>>> ifThenElse(X input) {
  return (final Predicate<X> pred) -> (final Function<X, Y> ifPresent) -> (final Function<X, Y> ifNotPresent) -> pred.test(input) ? ifPresent.apply(input) : ifNotPresent.apply(input);
}

这样你就可以说:

final String result = ifThenElse("fancy")
  .apply(input -> input.contains("fancy")) /* test      */
  .apply(input -> input.toUpperCase())     /* if-case   */
  .apply(input -> input.toLowerCase());    /* else-case */

Java 9引入了

如果存在一个值,则使用该值执行给定的操作,否则执行给定的基于空的操作。

参见Java 8备忘单中的优秀可选选项。

它为大多数用例提供了所有答案。

下面是简短的总结

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() - turning empty可选,默认T

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);

另一种解决方案是使用如下所示的高阶函数

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

你不能在ifPresent之后调用orElse,原因是,orElse是在可选对象上调用的,而ifPresent返回void。所以实现的最好方法是ifpresenttorelse。 它可以是这样的:

op.ifPresentOrElse( 
            (value) 
                -> { System.out.println( 
                         "Value is present, its: "
                         + value); }, 
            () 
                -> { System.out.println( 
                         "Value is empty"); }); 

所描述的行为可以通过使用Vavr(以前称为Javaslang)来实现,Vavr是Java 8+的对象函数库,它实现了大多数Scala构造(Scala是一种表现力更强的语言,在JVM上构建了更丰富的类型系统)。它是一个非常好的库,可以添加到Java项目中来编写纯函数式代码。

Vavr提供了Option单子,它提供了使用Option类型的函数,例如:

折叠:在两种情况下映射选项的值(已定义/空) onEmpty:当选项为空时允许执行一个可运行对象 Peek:允许使用选项的值(当定义时)。 与可选相反,它也是可序列化的,这意味着你可以安全地使用它作为方法参数和实例成员。

选项遵循单子法则,不同于Java的可选“伪单子”,并提供了更丰富的API。当然,你也可以从Java的Optional(或其他方式)中实现:Option.ofOptional(javaOptional) -Vavr专注于互操作性。

看这个例子:

// AWESOME Vavr functional collections (immutable for the gread good :)
// fully convertible to Java's counterparts.
final Map<String, String> map = Map("key1", "value1", "key2", "value2");

final Option<String> opt = map.get("nonExistentKey"); // you're safe of null refs!
        
final String result = opt.fold(
        () -> "Not found!!!",                // Option is None
        val -> "Found the value: " + val     // Option is Some(val)
);

此外,所有Vavr类型都可以转换为Java对应的类型,例如:Optional javaOptional = opt.toJava(),非常简单:)当然,转换也存在于另一种方式:Option Option = Option. ofoptional (javaOptional)。

注意:Vavr提供了一个io.vavr.API类,其中有很多方便的静态方法=)

进一步的阅读

空引用,十亿美元的错误

注意:这只是Vavr提供的一个非常小的例子(模式匹配,流也就是惰性评估列表,单体类型,不可变集合,…)