2014-10-28 48 views
6

我試圖在Java中使用flatMapOptional s。下面是一個簡單的例子:Java 8 flatMap + Optional.of不能編譯

List<String> x = Arrays.asList("a", "b", "c"); 
List<String> result = x.stream().flatMap((val) -> val.equals("b") ? Optional.empty() : Optional.of(val)).collect(Collectors.toList()); 

我從編譯器此錯誤消息:

Error:(10, 27) java: incompatible types: no instance(s) of type variable(s) T exist so that java.util.Optional<T> conforms to java.util.stream.Stream<? extends R> 

有什麼不對?下面是我嘗試在Scala中實現的例子:

List("a", "b", "c").flatMap(x => if (x == "b") None else Some(x)) 

它返回:

res2: List[String] = List(a, c) 

預期。

如何將其轉換爲Java以便編譯?

回答

2

沒有必要處理與Optional在這裏。

最簡單直接的解決方案是使用filter

List<String> result = x.stream() 
    .filter(val -> !val.equals("b")) 
    .collect(Collectors.toList()); 

如果你堅持要用flatMap,你只需要使用Stream代替Optional

List<String> result = x.stream().flatMap(
    val -> val.equals("b")? Stream.empty(): Stream.of(val)) 
    .collect(Collectors.toList()); 

如果你要處理不可避免地會產生Optional的操作,您必須將其轉換爲Stream以便使用Stream.flatMap

List<String> result = x.stream() 
    .map(val -> val.equals("b") ? Optional.<String>empty() : Optional.of(val)) 
    .flatMap(o->o.map(Stream::of).orElse(Stream.empty())) 
    .collect(Collectors.toList()); 
6

flatMap預計將輸入Stream的元素映射到不同的Stream。因此它必須返回一個Stream而不是Optional

因此,你應該做這樣的事情:

List<String> x = Arrays.asList("a", "b", "c"); 
List<Optional<String>> result = 
    x.stream() 
    .flatMap((val) -> 
        val.equals("b") ? Stream.of(Optional.empty()) : 
            Stream.of(Optional.of(val))) 
    .collect(Collectors.toList()); 

請注意,如果你的目標很簡單,就是(在你的榜樣「B」)擺脫一些值,你不需要完全可以使用Optional。你可以只過濾流:

List<String> result = 
    x.stream() 
    .filter (val -> !val.equals("b")) 
    .collect(Collectors.toList()); 

這樣,你不需要flatMap和你的輸出是List<String>而不是List<Optional<String>>

作爲霍爾格評論,返回的OptionalStream可以通過使用map代替flatMap被簡化的解決方案,因爲每個元素映射到單個Optional

List<String> x = Arrays.asList("a", "b", "c"); 
List<Optional<String>> result = 
    x.stream() 
    .map((val) -> val.equals("b") ? Optional.empty() : Optional.of(val)) 
    .collect(Collectors.toList()); 
+0

謝謝!通常我會過濾。在這種情況下(真實情況,不是簡單的玩具例子),我寧願使用Optionals,因爲過濾意味着要挖掘很多垃圾,我還必須在地圖階段進行挖掘。 – auramo 2014-10-28 15:31:07

+1

當流的每個元素都映射到一個'Optional'時,就不需要使用'flatMap'。只需使用'.map(val - > val.equals(「b」)?Optional.empty():可選。(val))' – Holger 2014-10-28 15:43:37

+0

@Holger你是對的。我沒有想過。我遵循OP的決定使用flatMap。 – Eran 2014-10-28 15:45:26