Optional 的 map() 和 filter() 操作类型

Meh*_*lik 2 java eager lazy-evaluation java-stream

map()filter()Optional懒样Stream

我如何确认它们的类型?

Hol*_*ger 8

aStream和 an之间有根本区别Optional

AStream封装了整个处理管道,在做任何事情之前收集所有操作。这允许实现选择不同的处理策略,具体取决于实际请求的结果。这也允许将修饰符像unordered()parallel()插入链中,因为在这一点上,到目前为止还没有做任何事情,所以我们可以改变后续实际处理的行为。

一个极端的例子是Stream.of(1, 2, 3).map(function).count(),它function在 Java 9 中根本不会处理,因为 的不变结果3可以在没有的情况下确定。

相反, anOptional只是一个值的包装器(如果不是空的)。每个操作都将立即执行,以返回Optional封装新值的新值或空值Optional。在 Java 8 中,所有返回 an Optional, ie map, flatMapor 的方法filter在应用于空可选时只会返回一个空可选,因此在链接它们时,空可选成为一种死胡同。

但是 Java 9 将引入Optional<T> or?(Supplier<? extends Optional<? extends T>>),当应用于空的可选项时,它可能会从供应商处返回一个非空的可选项。

由于 anOptional表示(可能不存在)值,而不是处理管道,因此您可以Optional根据需要多次查询相同的Optional值,无论查询返回新值还是最终值。

很容易验证。以下代码

Optional<String> first=Optional.of("abc");
Optional<String> second=first.map(s -> {
    System.out.println("Running map");
    return s + "def";
});
System.out.println("starting queries");
System.out.println("first: "+(first.isPresent()? "has value": "is empty"));
System.out.println("second: "+(second.isPresent()? "has value": "is empty"));
second.map("second's value: "::concat).ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

将打印

Optional<String> first=Optional.of("abc");
Optional<String> second=first.map(s -> {
    System.out.println("Running map");
    return s + "def";
});
System.out.println("starting queries");
System.out.println("first: "+(first.isPresent()? "has value": "is empty"));
System.out.println("second: "+(second.isPresent()? "has value": "is empty"));
second.map("second's value: "::concat).ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

证明映射函数是在任何其他查询之前立即计算的,并且first在我们map多次创建第二个 via和 query optionals之后,我们仍然可以查询可选项。

事实上,强烈建议isPresent()在调用之前先检查 via get()

没有等效的流代码,因为以Stream这种方式重用实例是无效的。但是我们可以证明在终端操作开始之前不会执行中间操作:

Stream<String> stream=Stream.of("abc").map(s -> {
    System.out.println("Running map");
    return s + "def";
});
System.out.println("starting query");
Optional<String> result = stream.findAny();
System.out.println("result "+(result.isPresent()? "has value": "is empty"));
result.map("result value: "::concat).ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

将打印

Running map
starting queries
first: has value
second: has value
second's value: abcdef
Run Code Online (Sandbox Code Playgroud)

显示在终端操作findAny()开始之前不评估映射函数。由于我们不能多次查询流,findAny()甚至使用Optional作为返回值,这允许我们对最终结果执行此操作。


同名操作之间还有其他语义差异,例如,如果映射函数的计算结果为,Optional.map则返回空Optionalnull。对于流,传递给map返回的函数null或非null值没有区别(这就是为什么我们可以在不知道是否返回的情况下计算元素)。


Eug*_*ene 5

 String r = Optional.of("abc")
            .map(s -> {
                System.out.println("Running map");
                return s + "def";
            })
            .filter(s -> {
                System.out.println("First Filter");
                return s.equals("abcdef");
            })
            .map(s -> {
                System.out.println("mapping");
                return s + "jkl";
            })
            .orElse("done");

    System.out.println(r);
Run Code Online (Sandbox Code Playgroud)

运行这将产生:

运行map, First Filter, mapping abcdefjkl

另一方面运行这个:

String r = Optional.of("mnt") //changed
            .map(s -> {
                System.out.println("Running map");
                return s + "def";
            })
            .filter(s -> {
                System.out.println("First Filter");
                return s.equals("abcdef");
            })
            .map(s -> {
                System.out.println("mapping");
                return s + "jkl";
            })
            .orElse("done");
Run Code Online (Sandbox Code Playgroud)

运行地图,第一个过滤器,完成

我一直认为,既然map只是基于以前的执行filter,这将被考虑lazy。事实证明这不是真的

 Optional.of("s").map(String::toUpperCase)
 Stream.of("test").map(String::toUpperCase)
Run Code Online (Sandbox Code Playgroud)

mapOptional将得到执行; 而一个 fromStream不会。

编辑

去这里投票另一个答案。这是因为另一个而编辑的。