2016-04-27 81 views
0

我想總結第一千個素數。當我嘗試這...在可選項上使用get()是不好的做法嗎?

System.out.println(getFirstThousandPrimes().stream() 
              .reduce(Integer::sum) 
              .get() 
    ); 

IntelliJ建議我檢查isPresent(),但是這甚至可能嗎?

另一種選擇是使用.orElse(-1),但我不想返回任何東西。我應該拋出一個異常?

回答

1

在您的具有空輸入的特定測試中完全有效:零數之和爲零。因此,您可以使用.reduce(Integer::sum).orElse(0)或完全擺脫.reduce(0, Integer::sum)之類的期權。

另外請注意,您可以轉換成原始數據流,並使用sum()方法直接:

getFoos().stream().mapToInt(x -> x).sum(); 

這樣,你當然還可以得到0,如果輸入的是空的。

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); 

第二方法比第一種方法更簡潔高效。

希望這回答你的問題。

1

不,使用.get()而不使用.ifPresent不一定是壞習慣。這歸結於您正在實施的邏輯。如果爲空Optional是一種特殊情況,依靠.get()拋出NoSuchElementException是完全合適的。

所以你應該問自己的問題是,如果getFirstThousandPrimes()返回一個空列表,你的代碼應該做什麼。

相關問題