Я хочу просуммировать первую тысячу простых чисел. Когда я пробую это ...
System.out.println(getFirstThousandPrimes().stream()
.reduce(Integer::sum)
.get()
);
IntelliJ предлагает мне проверить isPresent (), но возможно ли это?
Другой вариант - использовать .orElse (-1), но я не хочу ничего возвращать. Должен ли я выбросить исключение?
3 ответа
В вашем конкретном тесте с пустым вводом вполне допустимо: сумма нулевых чисел равна нулю. Таким образом, вы можете использовать .reduce(Integer::sum).orElse(0)
или полностью отказаться от таких опций, как .reduce(0, Integer::sum)
.
Также обратите внимание, что вы можете преобразовать в примитивный поток и напрямую использовать метод sum()
:
getFoos().stream().mapToInt(x -> x).sum();
Таким образом, вы, конечно, также получите 0, если вход пуст.
При уменьшении потока до аргумента существует вероятность, что поток будет пустым, и для обработки этого случая вводится Optional
. Есть еще один метод reduce (), который принимает аргумент идентичности и, таким образом, уменьшает возвращаемый Optional
, потому что в случае пустого потока идентичность будет возвращена.
Но, сосредоточившись на вашей задаче, я бы рекомендовал использовать специальный сборщик для разделения простых и непростых чисел, а затем суммировать первые n чисел.
Некоторое время назад я реализовал сборщик простых и непростых чисел, и реализация выглядит следующим образом:
public class PrimeNumberCollector implements Collector<Integer,
Map<Boolean, List<Integer>>,
Map<Boolean, List<Integer>>> {
@Override
public Supplier<Map<Boolean, List<Integer>>> supplier() {
return () -> new HashMap<Boolean, List<Integer>>() {{
put(Boolean.TRUE, new ArrayList<>());
put(Boolean.FALSE, new ArrayList<>());
}};
}
@Override
public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
return (Map<Boolean, List<Integer>> acc, Integer candidate) -> acc.get(isPrime(candidate))
.add(candidate);
}
@Override
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
return (Map<Boolean, List<Integer>> firstMap, Map<Boolean, List<Integer>> secondMap) -> {
firstMap.get(Boolean.TRUE).addAll(secondMap.get(Boolean.TRUE));
firstMap.get(Boolean.FALSE).addAll(secondMap.get(Boolean.FALSE));
return firstMap;
};
}
@Override
public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH));
}
private static boolean isPrime(final int candidate) {
return IntStream.rangeClosed(2, (int) Math.sqrt(candidate)).noneMatch(i -> candidate % i == 0);
}
}
И его использование:
@Test
public void collectingPrimeNumbersWithCustomCollector() {
Map<Boolean, List<Integer>> primesNumbersMap = IntStream.rangeClosed(1, 1_000_000)
.boxed()
.collect(CustomCollectors.primeNumbers()); //or new PrimeNumbersCollector()
Utils.printLine("Prime numbers between 1 - 1_000_000:");
Utils.printLine(primesNumbersMap.get(Boolean.TRUE));
}
Затем вы можете limit(1000)
и sum(0, BinaryOperator)
все простые числа до достижения предела количества.
В качестве альтернативы вы можете использовать следующий метод для фильтрации потока чисел, чтобы выбрать только простые числа и суммировать их:
private static boolean isPrime(final int candidate) {
return IntStream.rangeClosed(2, (int) Math.sqrt(candidate)).noneMatch(i -> candidate % i == 0);
}
Использование будет выглядеть следующим образом:
Stream.iterate(1L, i -> i + 1) //iterate with sequential numbers
.filter(MyFancyClass::isPrime)
.limit(1000)
.reduce(0L, Long::sum);
Второй подход более лаконичен и эффективен, чем первый.
Надеюсь, что это ответ на ваш вопрос.
Нет, использование .get()
без .ifPresent
- не всегда плохая практика. Все сводится к логике, которую вы реализуете. Если пустой Optional
является исключительным условием, совершенно уместно полагаться на .get()
для выдачи NoSuchElementException
.
Поэтому вопрос, который вы должны задать себе, - что именно должен делать ваш код, если getFirstThousandPrimes()
возвращает пустой список.
Похожие вопросы
Новые вопросы
nullreferenceexception
Исключение .NET, возникающее при попытке сослаться (или использовать) на нулевой или неинициализированный объект.