我想總結第一千個素數。當我嘗試這...在可選項上使用get()是不好的做法嗎?
System.out.println(getFirstThousandPrimes().stream()
.reduce(Integer::sum)
.get()
);
IntelliJ建議我檢查isPresent(),但是這甚至可能嗎?
另一種選擇是使用.orElse(-1),但我不想返回任何東西。我應該拋出一個異常?
我想總結第一千個素數。當我嘗試這...在可選項上使用get()是不好的做法嗎?
System.out.println(getFirstThousandPrimes().stream()
.reduce(Integer::sum)
.get()
);
IntelliJ建議我檢查isPresent(),但是這甚至可能嗎?
另一種選擇是使用.orElse(-1),但我不想返回任何東西。我應該拋出一個異常?
在您的具有空輸入的特定測試中完全有效:零數之和爲零。因此,您可以使用.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()
返回一個空列表,你的代碼應該做什麼。