2017-05-26 22 views
1

map()filter()Optional是否像Stream一样懒?地图类型()和过滤器()操作的可选

我该如何确认他们的类型?

+1

你可以通过在地图或过滤器表达式中记录某些东西,然后检查什么时候记录东西来轻松验证。 – luk2302

+0

一行代码会更有帮助:) –

+2

不,最有帮助的将是你自己想出来,这样你学到最多。 – luk2302

回答

2

StreamOptional之间存在根本差异。

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

一个极端的例子是Stream.of(1, 2, 3).map(function).count(),这将不处理function中的Java 9在所有,作为3不变结果可以在没有被确定。

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

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

由于一个Optional代表(可能是不存在的)价值,而不是处理管道,您可以查询你想的一样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); 

将打印

Running map 
starting queries 
first: has value 
second: has value 
second's value: abcdef 

证明映射函数立即评估,任何其他查询之前,而我们,我们通过map创造了第二后,仍然可以查询first可选查询选项多次。

实际上,它是强烈推荐首先通过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作为返回值,这使我们可以用最终结果做到这一点。


同名的操作之间还存在其他语义差异,例如,如果映射函数评估为null,则Optional.map将返回空的Optional。对于一个流,传递给map的函数返回null或非null值(这就是为什么我们可以在不知道它是否确定的情况下对其进行计数的原因)没有区别。

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

Optionalmap将得到执行;而从Stream不会。

编辑

去和赞成票这里的其他答案。这是由于另一个编辑。

+0

三天没有异议......所有你已经证明的是,一个空的'可选的'不评估映射函数。这不需要被认为是“流路”。想想一个'HashSet' ...在你删除所有元素后,处理所有元素的方法变成空操作。这并不能证明这些行动是渴望还是懒惰。这是最好的说明'可选'操作是*不懒惰* – Holger

+0

也请参见http://ideone.com/TJ6p5G – Holger

+0

@Holger我有一个提示我错过了什么,thx回到这里。我一直认为可选的'filter.filter'会算作懒惰,因为第二个过滤器不是基于第一个过滤器进行评估的。 – Eugene