【Java】検証の結果、for文より拡張for文の方が遅かった

javaな空

先日こんなツイートをしました。

for文より拡張for文の方がどのくらい速くなるのか気になったので、実際にソースを書いて計測してみました。

すると意外な結果になったので、思わず記事にしちゃいました。

結論から言うと、for文より拡張for文の方が遅かったんです!

拡張for文の方が速くなるとずっと思い込んでいたので、この結果にはショックを隠しきれません。

どのように検証し、そしてどんな速度結果になったのかを今回お伝えしていきます。

for文と拡張for文の速度検証①:ArrayList

検証にあたって、こんなプログラムを書きました。

  • ループ回数は1万回
  • ループにはArrayListを使用
  • ideone.com」で実行
  • 5回実行し、その平均で比較

1)通常のfor文を実行

以下が、実際に流したプログラムのソースコードです。

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

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

/* 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
    {
	int maxNum = 10000;
	ArrayList<Integer> list = new ArrayList<>(maxNum);

	for(int i=0; i<maxNum; i++){
	    list.add(new Integer(i));
	}

	long sTime = System.nanoTime();
	for(int j=0; j<list.size(); j++){
	    Integer elm = list.get(j);
	}
	long eTime = System.nanoTime();
	System.out.println(eTime - sTime);
    }
}
<実行結果(ナノ秒)>
1回目:2529297
2回目:1773775
3回目:1562873
4回目:1737851
5回目:1758509
平均:1872461

2)拡張for文を実行

プログラムを下記のようにfor文→拡張for文へ書き換えて実行してみました。

for(int j=0; j<list.size(); j++){
    Integer elm = list.get(j);
}
    ↓
for(Integer elm : list){
    subList.add(elm);
}
<実行結果(ナノ秒)>
1回目:2587073
2回目:2647290
3回目:2624908
4回目:2600004
5回目:2352567
平均:2562368.4

3)for文と拡張for文の結果を比較

for文拡張for文
1回目25292972587073
2回目17737752647290
3回目15628732624908
4回目17378512600004
5回目17585092352567
平均18724612562368.4
単位はナノ秒

予想に反して、for文の方が速いことがわかります。

な…なんで?

オマケ)ループ回数を事前に取得しておくパターン

通常のfor文で、ArrayListのサイズを取得してループ回数を決めていますが、サイズをループの外で先に取得しておくと速くなると聞いたことがあります。

それも実際に試してみました。

for(int j=0; j<list.size(); j++){
    Integer elm = list.get(j);
}
    ↓
int listSize = list.size();
for(int j=0; j<listSize; j++){
    Integer elm = list.get(j);
}
<実行結果(ナノ秒)>
1回目:1637113
2回目:2122828
3回目:1654173
4回目:1462252
5回目:1495925
平均:1674458.2
for文for文
(配列サイズ取得はループ外)
1回目25292971637113
2回目17737752122828
3回目15628731654173
4回目17378511462252
5回目17585091495925
平均18724611674458.2
単位はナノ秒

ループ外でリストサイズを取得した方が、基本的には速くなるようです。

こちらは予想通りの結果になりましたね。

for文と拡張for文の速度検証②:配列

もしかしてArrayListを使ったからダメだったのかと思い、プログラムを配列使用に書き換えて実験してみました。

  • ループ回数は1万回
  • ループには配列を使用
  • ideone.com」で実行
  • 5回実行し、その平均で比較

1)通常のfor文を実行

まずは通常のfor文を計測してみます。

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

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

/* 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
    {
	int maxNum = 10000;
	int[] list = new int[maxNum];

	for(int i=0; i<maxNum; i++){
	    list[i] = i;
	}

	long sTime = System.nanoTime();
	for(int j=0; j<list.length; j++){
	    int elm = list[j];
	}
	long eTime = System.nanoTime();
	System.out.println(eTime - sTime);
    }
}
<実行結果(ナノ秒)>
1回目:144446
2回目:176494
3回目:144433
4回目:144435
5回目:140681
平均:150097.8

2)拡張for文を実行

プログラムを下記のようにfor文→拡張for文へ書き換えて実行してみました。

for(int j=0; j<list.length; j++){
    int elm = list[j];
}
    ↓
for(int elm : list){
}
<実行結果(ナノ秒)>
1回目:145408
2回目:134025
3回目:156209
4回目:145725
5回目:148039
平均:145881.2

3)for文と拡張for文の結果を比較

for文拡張for文
1回目144446145408
2回目176494134025
3回目144433156209
4回目144435145725
5回目140681148039
平均150097.8145881.2
単位はナノ秒

配列の場合は、拡張for文の方がほんの少し速いという結果になりました。

ArrayListと配列では結果が違うのは、面白いですね。

オマケ)ループ回数を事前に取得しておくパターン

for(int j=0; j<list.length; j++){
    int elm = list[j];
}
    ↓
int listSize = list.length;
for(int j=0; j<listSize; j++){
    int elm = list[j];
}
<実行結果(ナノ秒)>
1回目:199079
2回目:127925
3回目:134707
4回目:154453
5回目:131353
平均:149503.4
for文for文
(配列サイズ取得はループ外)
1回目144446199079
2回目176494127925
3回目144433134707
4回目144435154453
5回目140681131353
平均150097.8149503.4
単位はナノ秒

こちらもほんの少しですが、ループ外でサイズを取得した方が速い結果になりました。

ですが速度が不安定なので、配列の場合はわざわざループ外で取得しなくてもいいのかも。

まとめ

ポイントとメモ

全ての場合において拡張for文が最速なのかと思っていましたが、どうやら違ったようですね。

どれが速いのか迷った時は、とりあえずループ外でサイズを取得するfor文にしておけば良さそうです。

まぁ後々になってリストサイズやループ回数が必要になってくる場合があるので、拡張for文を使わない方が無難なのかもしれません。

ArrayListを使う場合
for文(サイズ取得はループ外) < for文 < 拡張for文

配列を使う場合
拡張for文 < for文(サイズ取得はループ外) < for文

コメント

タイトルとURLをコピーしました