[Java] IteratorをStreamにする


# 目的

- 自力で任意のストリームを作る最善の方法…はわかりませんが、とりあえず Iterator があれば Stream にできます
- すぐ忘れるのでメモ

# サンプル

```java
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

//...

// Iterator を Stream にする
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
Stream<String> stream = StreamSupport.stream(spliterator, false);
```

`Spliterators.spliteratorUnknownSize()` の第２引数に渡しているものは characteristics というデータの特性です。以下の値の論理和を指定します。

- ORDERED - 順番が決まっている(例: List, LinkedHashSet, TreeSet)
- DISTINCT - 重複なし(例: Set)
- SORTED - ソートされている(例: SortedSet)
- SIZED - サイズが決まっている(例: Collection)
- NONNULL - null が含まれていない
- IMMUTABLE - 変更不可能
- CONCURRENT - マルチスレッドで更新可能
- SUBSIZED - Spliteratorを分割した後でも、分割後Spliteratorのサイズが決まっている(暗黙的にSIZEDも指定される)

生成するデータの特性に応じて設定すると良いかと思います。

もし、サイズが決まっている場合（SIZED and/or SUBSIZED)には、 `Spliterators.spliteratorUnknownSize()` ではなく、 `Spliterators.spliterator()` を使う必要があります。

```java
Spliterator<String> spliterator = Spliterators.spliterator(iterator, size, Spliterator.SIZED);
```


また、 `StreamSupport.stream()` の第２引数はパラレルストリームかどうかの指定です。

# 実装例

あまり賢くないロジックかもしれないけど。

```java
/**
 * 有限ストリームを生成
 *
 * @param generator
 *            データを生成するサプライヤー. null を返した場合に終端と判断
 * @return ストリーム
 */
public static <T> Stream<T> stream(Supplier<T> generator) {
	Iterator<T> iterator = new SupplierIterator<T>(generator);
	Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.NONNULL);
	Stream<T> stream = StreamSupport.stream(spliterator, false);
	return stream;
}

/**
 * Supplier を Iterator 化.<br>
 * Supplier が null を返したら終端だと判断します。
 *
 * @param <T>
 *            要素の型
 */
public static class SupplierIterator<T> implements Iterator<T> {
	/** データを生成するサプライヤー */
	private final Supplier<T> generator;
	/** 終端まで処理済みの場合に真 */
	private boolean isEof = false;
	/** 先読みした値. 先読みしていなければnull */
	private T nextValue;

	/**
	 * コンストラクタ
	 *
	 * @param generator サプライヤー
	 * @throws NullPointerException 引数が null の場合
	 */
	public SupplierIterator(Supplier<T> generator) {
		this.generator = Objects.requireNonNull(generator);
	}

	@Override
	public boolean hasNext() {
		if (!isEof && nextValue == null) {
			// EOF でなく、先読みしていない場合
			nextValue = generator.get();
            // 読んだデータが null なら終端と判断
			isEof = (nextValue == null);
		}
        return !isEof;
	}

	@Override
	public T next() {
		if (hasNext()) {
			T value = nextValue;
			nextValue = null;
			return value;
		}
		throw new NoSuchElementException();
	}
}
```

# それ以外のストリームの作り方

がんばってイテレータを作らなくても、他の方法でストリームを作ることもできます。

## Stream#of(), Collection#stream(), Arrays#stream()

```java
Stream<String> stream0 = Stream.of("A", "B", "C");

List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream1 = list.stream();

String[] array = { "A", "B", "C" };
Stream<String> stream2 = Arrays.stream(array);
```

## Stream#builder()

```java
Stream.Builder<String> builder = Stream.builder();
builder.accept("A");
builder.accept("B");
builder.accept("C");
Stream<String> stream3 = builder.build();

Stream<String> stream4 = Stream.<String> builder()
		.add("A")
		.add("B")
		.add("C")
		.build();
```

## Stream#generate()

```java
Supplier<String> generator = () -> method();
Stream<String> stream5 = Stream.generate(generator).limit(5);
```

無限ストリームになります。

## Stream#iterate()

```java
Stream<String> stream6 = Stream.iterate("S", (s) -> s + s);
stream6.limit(10).forEach(s -> {
    System.out.println(s);
});
```

無限ストリームになります。