可选的map()和filter()操作的类型

时间:2017-05-26 12:46:09

标签: java java-stream lazy-evaluation eager

map()的{​​{1}}和filter()是否像Optional一样懒惰?

我如何确认他们的类型?

2 个答案:

答案 0 :(得分:4)

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

运行它将产生:

  

运行地图,第一个过滤器,映射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");
  

运行地图,第一次过滤,完成

我一直认为,由于map仅基于之前的filter执行,因此会将其视为lazy。事实证明这是不正确

 Optional.of("s").map(String::toUpperCase)
 Stream.of("test").map(String::toUpperCase)

来自map的{​​{1}}将被执行;而来自Optional的那个不会。

编辑

在这里继续投票给另一个答案。这是因为另一个编辑。

答案 1 :(得分:4)

02/Jan/1990Stream之间存在根本区别。

Optional封装整个处理管道,在执行任何操作之前收集所有操作。这允许实现根据实际请求的结果来选择不同的处理策略。这也允许在链中插入像Streamunordered()这样的修饰符,因为到目前为止还没有做任何事情,所以我们可以改变后续实际处理的行为。

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

相比之下,3只是一个值的包装(如果不是空的话)。每个操作都将立即执行,以返回封装新值的新Optional或空Optional。在Java 8中,返回Optional的所有方法,即OptionalmapflatMap,只会在应用于空的可选项时返回空的可选项,因此在链接时他们,空的选择变成了一种死胡同。

但Java 9将引入filter,当应用于空的可选项时,它可能会从供应商处返回非空的可选项。

由于Optional<T> or​(Supplier<? extends Optional<? extends T>>)表示(可能不存在)值而不是处理管道,因此无论查询是否返回新{{1},您都可以多次查询OptionalOptional。或者是最终值。

很容易验证。以下代码

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

演示在任何其他查询之前立即评估映射函数,并且在我们多次创建第二个Running map starting queries first: has value second: has value second's value: abcdef 和查询选项后,我们仍然可以查询first可选项。

事实上,强烈建议首先通过map进行检查,然后再致电isPresent()

没有等效的流代码,因为以这种方式重用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);

显示在终端操作starting query Running map result has value result value: abcdef 开始之前未评估映射函数。由于我们无法多次查询流,findAny()甚至使用findAny()作为返回值,这样我们就可以使用最终结果来执行此操作。

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