2014-10-28 31 views
6

Tôi đang cố gắng để flatMapOptional s trong Java. Dưới đây là một ví dụ đơn giản:Java 8 flatMap + Optional.of không biên dịch

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

tôi nhận được thông báo lỗi này từ trình biên dịch:

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> 

Có chuyện gì vậy? Dưới đây là một ví dụ về những gì tôi đang cố gắng để đạt được trong Scala:

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

Nó trả về:

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

như mong đợi.

Làm cách nào để chuyển đổi thành Java để biên dịch?

Trả lời

2

Không cần để đối phó với Optional tại đây.

Giải pháp đơn giản nhất thẳng về phía trước là sử dụng filter

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

Nếu bạn nhấn mạnh vào việc sử dụng flatMap, bạn chỉ nên sử dụng Stream thay vì Optional:

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

Nếu bạn phải đối phó với một hoạt động không thể tránh khỏi tạo ra một Optional, bạn sẽ phải chuyển đổi nó thành một số Stream để sử dụng 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 dự kiến ​​sẽ ánh xạ phần tử của dữ liệu nhập Stream vào một khác Stream. Do đó, nó phải trả lại Stream và không phải là Optional.

Do đó, bạn nên làm một cái gì đó như thế này:

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

Lưu ý rằng nếu mục tiêu của bạn chỉ đơn giản là để thoát khỏi một số giá trị ("b" trong ví dụ của bạn), bạn không cần phải sử dụng tùy chọn ở tất cả. Bạn chỉ có thể lọc Luồng:

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

Bằng cách này bạn không cần flatMap và đầu ra của bạn là một List<String> thay vì một List<Optional<String>>.

Như Holger nhận xét, các giải pháp mà trả về một Stream của Optional s có thể được đơn giản hóa bằng cách sử dụng map thay vì flatMap, vì mỗi phần tử được ánh xạ vào một đơn 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

Cảm ơn! Bình thường tôi sẽ lọc. Trong trường hợp này (trường hợp thực sự, không phải là ví dụ đồ chơi đơn giản) Tôi muốn sử dụng Optionals vì lọc sẽ có nghĩa là đào qua rất nhiều crap mà tôi cũng sẽ phải làm trong bản đồ-giai đoạn. – auramo

+1

Khi mọi phần tử của luồng được ánh xạ tới chính xác một 'Tùy chọn', không cần sử dụng' flatMap'. Chỉ cần sử dụng '.map (val -> val.equals (" b ")? Optional.empty(): Tùy chọn.của (val)) ' – Holger

+0

@ Holger Bạn hoàn toàn đúng. Tôi không nghĩ về nó. Tôi đã theo quyết định của OP để sử dụng một flatMap. – Eran

Các vấn đề liên quan