Почему это использование Stream:: flatMap не так?
Я ожидал, что смогу использовать Stream:: flatMap, как это
public static List<String> duplicate(String s) {
List<String> l = new ArrayList<String>();
l.add(s);
l.add(s);
return l;
}
listOfStrings.stream().flatMap(str -> duplicate(str)).collect(Collectors.toList());
Но я получаю следующую ошибку компилятора
Test.java:25: ошибка: несовместимые типы: не может вызывать переменную типа (ов) R listOfStrings.stream(). FlatMap (str → duplicate (str)). Collect (Collectors.toList());
(несоответствие аргументов, неправильный тип возврата в выражении лямбда Список не может быть преобразован в Stream)
где R, T - переменные типа: R extends Объект, объявленный в методе flatMap (Function > ) T extends Объект, объявленный в интерфейсе Stream
В scala я могу сделать то, что, как я считаю, эквивалентно
scala> List(1,2,3).flatMap(duplicate(_))
res0: List[Int] = List(1, 1, 2, 2, 3, 3)
Почему это не допустимое использование flatMap в java?
Ответы
Ответ 1
В выражении лямбда в flatMap
необходимо вернуть Stream
, что видно из аргумента flatMap
, который имеет тип Function<? super T, ? extends Stream<? extends R>>
.
Следующий код будет компилироваться и работать нормально:
listOfStrings.stream()
.flatMap(str -> duplicate(str).stream()) // note the .stream() here
.collect(Collectors.toList());
поскольку выражение лямбда str -> duplicate(str).stream()
имеет тип Function<String, Stream<String>>
.
Ответ 2
Если вы хотите дублировать каждый объект в потоке несколько раз, вам не нужно тратить память на это с помощью дополнительного ArrayList
. Существует несколько более быстрых и быстрых альтернатив.
-
Создайте новый поток, используя Stream.generate
, затем ограничьте его:
listOfStrings.stream()
.flatMap(str -> Stream.generate(() -> str).limit(2))
.collect(Collectors.toList());
-
Сгенерировать последовательность чисел через IntStream.range
и сопоставить их с одной строкой:
listOfStrings.stream()
.flatMap(str -> IntStream.range(0, 2).mapToObj(i -> str))
.collect(Collectors.toList());
-
Используйте старый добрый Collections.nCopies
:
listOfStrings.stream()
.flatMap(str -> Collections.nCopies(2, str).stream())
.collect(Collectors.toList());
Если вы уверены, что вы всегда будете дублировать ровно два раза, есть самая короткая альтернатива:
listOfStrings.stream()
.flatMap(str -> Stream.of(str, str))
.collect(Collectors.toList());