Как выполнить вложенные операторы if, используя Java 8/lambda?
У меня есть следующий код и вы хотите его реализовать с помощью лямбда-функций только для удовольствия. Можно ли это сделать с помощью основных операций агрегата?
List<Integer> result = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
if (10 % i == 0) {
result.add(i);
if (i != 5) {
result.add(10 / i);
}
}
}
Использование лямбда:
List<Integer> result = IntStream.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
// a map or forEach function here?
// .map(return 10 / i -> if i != 5)
.collect(Collectors.toList());
Ответы
Ответ 1
Существенное замечание здесь заключается в том, что ваша проблема связана с неизоморфным преобразованием: один элемент ввода может отображать нуль, один или два выходных элемента. Всякий раз, когда вы это замечаете, вы должны немедленно начать поиск решения, которое включает flatMap
вместо map
, потому что это единственный способ добиться такого общего преобразования. В вашем конкретном случае вы можете сначала применить filter
для сопоставления элементов с одним нулем, затем flatMap
для сопоставления "один-два":
List<Integer> result =
IntStream.rangeClosed(1, 10)
.filter(i -> 10 % i == 0)
.flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
.boxed()
.collect(toList());
Ответ 2
Вы можете объявить тело лямбдой. Например:
Runnable run = () -> System.out.println("Hey");
Может быть
Runnable run = () -> {
System.out.println("Hey");
};
Внутри этого тела вы можете создавать вложенные операторы:
Runnable run = () -> {
int num = 5;
if(num == 5) {
System.out.println("Hey");
}
};
Ответ 3
Используйте flatMap
, поскольку вы пытаетесь добавить элементы в конвейер или отображение 1-ко-многим. Карта представляет собой сопоставление от одного к другому.
ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
.flatMap((Integer i) -> {return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);})
.collect(Collectors.toList());
В результате получается тот же список, что и
ArrayList<Integer> result2 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
if (10 % i == 0) {
result2.add(i);
if (i != 5) {
result2.add(10 / i);
}
}
}
В случае, если вам интересно, какой путь быстрее, метод цикла в 3 раза быстрее, чем использование потоков.
Benchmark Mode Cnt Score Error Units
testStreams.Bench.loops avgt 5 75.221 ± 0.576 ns/op
testStreams.Bench.streams avgt 5 257.713 ± 13.125 ns/op
Ответ 4
Вы можете сделать это:
List<Integer> result1 = IntStream
.rangeClosed(1, 10)
.boxed()
.filter(i -> 10 % i == 0)
.map(i -> (i != 5 ? Stream.of(i, 10 / i) : Stream.of(i)))
.flatMap(Function.identity())
.collect(Collectors.toList());
Ответ 5
Попробуйте использовать flatMap
:
List<Integer> result = IntStream.rangeClosed(1, 10)
.boxed()
.flatMap((i) -> {
List<Integer> results = new ArrayList<>();
if (10 % i == 0) {
results.add(i);
if (i != 5) {
results.add(10 / i);
}
}
return results.stream();
})
.collect(Collectors.toList());
См. http://ideone.com/EOBiEP