バッファリングしない方が速いときもある

前に書いたソースを見直していたら、こんなものがありました。
(指定のデータをクライアントに流すだけのサーブレットです)

OutputStream out = new BufferedOutputStream(response.getOutputStream());
InputStream in = new BufferedInputStream(new ByteArrayInputStream(data));

byte[] buf = new byte[BUF_SIZE];
while(in.read(buf) != -1){
  out.write(buf);
}
out.flush();

改めて見直してみると、無駄が・・・。

二重にバッファリングをしている

BufferedOutputStream を使っているのに、読み込み部分でもバッファリングをしています。
これだと、入力→配列に書き込み→配列に書き込み→出力という処理になってしまいます。

そこで、以下のように修正してみました。

int b;
while((b = in.read()) != -1){
  out.write(b);
}

これで約20%速くなりました*1

そもそもバッファリングいらない?

そもそもサーブレットのレスポンス(ServletResponse)には、バッファの設定が用意されています(ServletResponse#setBufferSize (Servlet API Documentation))。
そのため、BufferedOutputStream でデコレートする必要もありません。

ByteArrayInputStream はバッファリングの必要がない

ByteArrayInputStream はオーバヘッドがない*2ので、わざわざ BufferedInputStream でデコレートする必要がありません。
ここも、直接処理してしまっていいはずです。
(ここはパフォーマンス測定していないので、どのぐらい変わるかわからないですが・・・)

まとめ

OutputStream out = response.getOutputStream();
InputStream in = new ByteArrayInputStream(data);

int b;
while((b = in.read()) != -1){
  out.write(b);
}
out.flush();

処理もシンプルでかつ高速になりました。
作ったときは、とりあえずバッファを挟んでおけばいいと思っていたんですが、実際には注意しないと逆効果になるんですね・・・。

*1:転送速度が遅かったので、ちょっと顕著に出たのかもしれません

*2:構造がバッファとほぼ一緒で、ただ配列を読み取るだけです。