2016-08-10 2 views
2

Дано:Объединение списка <T> и списка <Optional<T>>

List<Integer> integers = new ArrayList<>(Arrays.asList(
      10, 12 
    )); 

    List<Optional<Integer>> optionalIntegers = Arrays.asList(
      Optional.of(5), 
      Optional.empty(), 
      Optional.of(3), 
      Optional.of(2), 
      Optional.empty() 
    ); 

    List<Integer> unwrappedOptionals = optionalIntegers.stream() 
      .filter(Optional::isPresent) 
      .map(Optional::get) 
      .collect(Collectors.toList()); 

    integers.addAll(unwrappedOptionals); 

Есть ли лучший способ разворачивания Optional с, или другой способ объединения их обоих в List<Integer>? Очень сложно собрать их в новый List, прежде чем делать addAll().

ответ

2

Вы можете использовать другую форму ifPresent

ifPresent(Consumer<T>) void 

С помощью простого Foreach можно было бы написать:

optionalIntegers.stream().forEach(optional -> optional.ifPresent(integers::add)); 
+0

Спасибо! Хотя каждый ответ правильный, я чувствовал, что это решение, которое я предпочитаю, и обозначил его соответствующим образом. Для меня лучше всего использовать замену 'isPresent' и' get' с 'ifPresent'. –

5

Если вы не хотите, чтобы создать промежуточный List, добавьте отфильтрованные элементы непосредственно к исходному integersList использованием forEach() вместо collect():

optionalIntegers.stream() 
     .filter(Optional::isPresent) 
     .map(Optional::get) 
     .forEach(integers::add); 

Или, как предложил Сергей Лагутин, вы можете использовать Optional «s map() и orElse() методы с flatMap():

optionalIntegers.stream() 
       .flatMap(o -> o.map(Stream::of) 
           .orElse(Stream.empty())) 
       .forEach(integers::add); 
+1

не уверен, что моя идея хороша, но мы объединить 'filter' и' map' с одной операцией 'flatMap':' flatMap (o -> o.map (поток :: of) .orElse (Stream.empty())) ' –

+1

@SergeyLagutin Это также работает. Я не уверен, что лучше. Благодаря! – Eran

2

Если вы хотите, чтобы объединить их в самостоятельную List<Integer> вы можете использовать Stream::concat как:

List<Integer> merged = Stream.concat(
     integers.stream(), 
     optionalIntegers.stream().filter(Optional::isPresent).map(Optional::get) 
    ).collect(Collectors.toList()); 
+0

Спасибо! Вероятно, у нас есть много случаев, когда обе «Стрим» доступны сразу, а использование concat будет более чистым. –

5

С новым Java-9 Optional.stream() метод можно записать следующим образом:

optionalIntegers.stream() 
       .flatMap(Optional::stream) 
       .forEach(integers::add); 

До Java-9 вы можете добавить такой метод в свой собственный служебный класс:

public class StreamUtil { 
    public static <T> Stream<T> fromOptional(Optional<T> opt) { 
     return opt.isEmpty() ? Stream.empty() : Stream.of(opt.get()); 
    } 
} 

И использовать его как это:

optionalIntegers.stream() 
       .flatMap(StreamUtil::fromOptional) 
       .forEach(integers::add); 
Смежные вопросы