StreamAPI版エラトステネスの篩

ラボでプログラミング課題で三回生が素数判定をMPIだのCUDAだので実装していたのですが、そういえばStreamAPIでエラトステネスの篩が書けない〜っていうブログがいくつかあったのを思い出しました。
forやifで書くアレをStream APIで書く - Java EE 事始め!
ゆっちのBlog » Java8 時代の素数の求め方

雰囲気エラトステネスの篩をStreamAPI+再帰で書いてみました。全然遅延実行されないので糞っぽい。

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
	public static void main (String[] args) throws java.lang.Exception
	{
		primeStream(100).forEach(System.out::println);
	}
	
	public static IntStream primeStream(int max) {
		return primes(IntStream.range(2, max));
	}
	
	private static IntStream primes(IntStream stream) {
		PrimitiveIterator.OfInt i = stream.iterator();
		if (!i.hasNext()) {return IntStream.empty();}
		int p = i.next();
		IntStream rest = stream(i);
		return IntStream.concat(IntStream.of(p), primes(rest.filter(n -> n % p != 0)));
	}
	
	private static IntStream stream(PrimitiveIterator.OfInt i) {
		return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(i, 0), false);
	}
}

ポイントはStream#findFirstで最初の値を取りだすと残りのデータが使えなくなってしまうけど、Stream#iteratorIteratorを取ってくると、残りのデータも使えるという点ですね。
IteratorからStreamに戻すためには、Spliterators#spliteratorXxxでSpliteratorを取ってきて、それをStreamSupport#streamに渡せばよいです。