我想总结前千个素数。当我试着这个......
System.out.println(getFirstThousandPrimes().stream()
.reduce(Integer::sum)
.get()
);
IntelliJ建议我检查isPresent(),但这是否可能?
另一种选择是使用.orElse(-1),但我不想返回任何东西。我应该抛出异常吗?
答案 0 :(得分:1)
不,在没有.get()
的情况下使用.ifPresent
并不一定是不好的做法。它归结为您正在实施的逻辑。如果空Optional
是一种例外情况,那么依靠.get()
投掷NoSuchElementException
是完全合适的。
因此,您应该问自己的问题是,如果getFirstThousandPrimes()
返回空列表,您的代码到底应该做什么。
答案 1 :(得分:1)
在您的特定测试中,空输入完全有效:零数之和为零。因此,您可以使用.reduce(Integer::sum).orElse(0)
或完全删除.reduce(0, Integer::sum)
等选项。
另请注意,您可以转换为原始流并直接使用sum()
方法:
getFoos().stream().mapToInt(x -> x).sum();
这样,如果输入为空,你当然也会得到0。
答案 2 :(得分:0)
通过将stream减少为参数,流可能会为空,并引入Optional
来处理这种情况。还有一个reduce()方法接受identity参数,从而减少返回的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);
第二种方法比第一种方法更简洁有效。
希望这能回答你的问题。