Java8での文字列連結

## これは何?
Stream使ってzipできないかなーと思って試行錯誤していたらちょっと気になったので書いた。

実際は[Java8時代の文字列連結まとめ - きしだのはてな](http://d.hatena.ne.jp/nowokay/20140409#1397010846)に便乗してたりして。

連結対象の文字列は配列として保持。`alpha`がそれ。実行時間は平均取るのが面倒臭かったので500万回のループを実行したときの結果。つまりあまり参考にならないので注意。

```java
static final String[] alpha = new String[]{
	"0", "1", "2", "3", "4", 
	"5", "6", "7", "8", "9",
	"a", "b", "c", "d", "e", 
	"f", "g", "h", "i", "j", 
	"k", "l", "m", "n", "o",
	"p", "q", "r", "s", "t",
	"u", "v", "w", "x", "y",
	"z"};
```

### 注記
なにか理由がない限り`Arrays.stream(T[])`の代わりに`Stream.of(T...)`を使ったほうがいいかもしれません。プリミティブな配列(`int[]`とか)じゃなければ`T`の配列は`T...`形式の引数をとるメソッドでは同一視されるため。
ビュー数やストック数が増えているので一応追記。(2014.11.2)

## 1. よくある文字列連結
```java
StringBuilder buf = new StringBuilder();
for(String str : alpha){
	buf.append(str);
}
buf.toString();
```
なんだかんだいってやっぱり速い。4552ms。

## 2. Stream APIで書く
```java
String str = Arrays.stream(alpha)
	.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
	.toString();
```
4620ms。まあ誤差の範囲。複数実行させたところ1を超すことだって何度かあった。よくわからんけどJIT最適化うんぬんかな？

## 3. もっと本格的に。
```java
String str = Arrays.stream(alpha).collect(Collectors.joining());
```
引用元忘れたけどどっかから持ってきたコード。5267ms。やっぱり標準APIでスッキリかけるのはコードの見通しが良くなっていい。

## 4. そもそも文字列joinだけならjava8からメソッド追加されてる
```java
String str = String.join("", alpha);
```
単純なのはこれでいいかもしれないけどStream APIとか取り出してる時点でこれは反則？6490ms。

## 5. StringBuilder使いなさい！と頭ごなしに叱られそうなコード
```java
String buf = "";
for(String str : alpha){
	buf += str;
}
```
まあ試行回数が少ないからね。7667ms。

## 6.魔窟。
```java
String str = String.join("", 
			Arrays.stream(alpha)
				.collect(Collectors.toList()) );
```
あとでコード見なおしてみれば、まあ無駄な操作が多すぎる。Stream API使って最初に書いたコード。可読性にも乏しいし、わざわざList<String>作ってからまたjoinかけてるところなんてまさに無意味。
実行したらあまりに遅くて、自分がわけわからんコーディングしてるのにStream APIのせいにして小一時間現実逃避してました。12114ms。

## 7. 関数型だぞー。すごいぞー。かっこいいぞー。
```java
String str = Arrays.stream(alpha).reduce("", String::concat);
```
俺は関数型の人間なんだ！fold(reduce)使いこなしてやったぜ！！どうだ参ったか！
関数型プログラミングのセミナー帰りのノリと勢いで書きそうなコード。reduceの代わりにcollectを使えば速いのに気がついてないご様子。
**注釈** reduceは終端操作だが、Stringを返すようにしなければならず、collectと異なりStringBuilderが使えない
ここまでで一番実行速度が遅いコードで、13015ms。（13秒!?）

P.S. 関数型プログラミング畑のかた、侮辱しているわけではありません。しかしながら十中八九気分を害すると思うのでここでお詫びさせていただきます。申し訳ありません。

## コード
~~~ java
import java.lang.System;
import java.lang.String;
import java.lang.StringBuilder;
import java.util.Arrays;
import java.util.stream.Stream;
import java.util.stream.Collectors;

public class Test{
	static final String[] alpha = new String[]{
		"0", "1", "2", "3", "4", 
		"5", "6", "7", "8", "9",
		"a", "b", "c", "d", "e", 
		"f", "g", "h", "i", "j", 
		"k", "l", "m", "n", "o",
		"p", "q", "r", "s", "t",
		"u", "v", "w", "x", "y",
		"z"};
	static long loop = 5000000;

	public static void main(String[] args){
		long span;
		/* 1: よくある文字列連結 ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			StringBuilder buf = new StringBuilder();
			for(String str : alpha){
				buf.append(str);
			}
			buf.toString();
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //4552

		/* 2: 1のStream API版? ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String str = Arrays.stream(alpha)
				.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
				.toString();
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //4620

		/* 3: collect使ってみる ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String str = Arrays.stream(alpha).collect(Collectors.joining());
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //5267

		/* 4: そもそも文字列joinだけならjava8からメソッド追加されてる ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String str = String.join("", alpha);
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //6490

		/* 5: StringBuilder使いなさい！と頭ごなしに叱られそうなコード ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String buf = "";
			for(String str : alpha){
				buf += str;
			}
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //7667

		/* 6: 最初に書いた残念コード ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String str = String.join("", 
						Arrays.stream(alpha)
							.collect(Collectors.toList()) );
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //12114

		/* 7: 高階関数学んだからという理由で、6の次に書いたクソコード ****/
		span = System.currentTimeMillis();
		for(long i=0; i<loop; i++){
			String str = Arrays.stream(alpha).reduce("", String::concat);
		}
		span = System.currentTimeMillis()-span;
		System.out.println(span); //13015
	}
}
~~~

実行結果

```shell-session
user@ubuntu:~$ java8 Test
4552
4620
5267
6490
7667
12114
13015
```