HashSet<>を配列にするのは、どのやり方が速い？

HashSetを配列にする方法はいろいろあるかと思います。

toArrayを使う場合はこんな感じでしょうか。

```java:toArray
hashSet -> hashSet.toArray(new Integer[hashSet.size()])
```

for文で実直に回す場合は、ちょっと長いですね。

```java:enhancedFor
hashSet -> {
    final Integer[] result = new Integer[hashSet.size()];
    int i = 0;

    for (Integer v : hashSet) {
        result[i++] = v;
    }
}
```

streamはこんなんでしょうか。

```java:stream
hashSet -> hashSet.stream().toArray(size -> new Integer[size])
```

ここでは上記3つの方法を比較してみました。

# ソース全体

要素10000個のHashSetを100万回配列にして、その平均時間を出力します。

```java:com.example.HashSet2Array.java
package com.example;

import java.util.HashSet;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 *
 * @author sengoku
 */
public class HashSet2Array {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        final int examCount = 1000000;
        final int hasSize = 10000;

        final Consumer<HashSet<Integer>> toArray
                = hashSet -> hashSet.toArray(new Integer[hashSet.size()]);
        
        final Consumer<HashSet<Integer>> enhancedFor = hashSet -> {
            final Integer[] result = new Integer[hashSet.size()];
            int i = 0;

            for (Integer v : hashSet) {
                result[i++] = v;
            }
        };

        final Consumer<HashSet<Integer>> stream
                = hashSet -> hashSet.stream().toArray(size -> new Integer[size]);

        new HashSet2Array("toArray", examCount, hasSize, toArray);
        new HashSet2Array("enhanced for", examCount, hasSize, enhancedFor);
        new HashSet2Array("stream", examCount, hasSize, stream);
    }

    public HashSet2Array(
            final String message,
            final int examCount,
            final int hashSize,
            final Consumer<HashSet<Integer>> consumer) {

        final HashSet<Integer> hashSet = createHashSet(hashSize);

        final Double result = Stream
                .iterate(1, x -> x + 1)
                .limit(hashSize)
                .collect(Collectors.averagingLong(x -> execAndMeasure(consumer, hashSet)));

        System.out.println(message + " result: " + result);
    }

    private HashSet<Integer> createHashSet(final int size) {
        final HashSet<Integer> hashSet = new HashSet<>();

        IntStream.range(1, size).forEach(i -> hashSet.add(i));

        return hashSet;
    }

    private long execAndMeasure(final Consumer<HashSet<Integer>> consumer, final HashSet<Integer> hashSet) {
        final long start = System.nanoTime();

        consumer.accept(hashSet);

        return System.nanoTime() - start;
    }
}

```

# 実行環境

Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

# 実行結果

結果の数値は実行時間です。数値が小さいほど速いです。

```
toArray result: 168829.2181
enhanced for result: 114511.2577
stream result: 159047.3653
```

意外にtoArrayが遅いのは、結構複雑なことしてるせいですね。
↓
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/AbstractCollection.java#L173

単純にfor文回すのが一番速くなるのも納得です。


# 考察

よっぽどシビアなパフォーマンス要件でない限り、一番読みやすいやり方を選んだほうがよさげです。