先日こんなツイートをしました。
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回目 | 2529297 | 2587073 |
2回目 | 1773775 | 2647290 |
3回目 | 1562873 | 2624908 |
4回目 | 1737851 | 2600004 |
5回目 | 1758509 | 2352567 |
平均 | 1872461 | 2562368.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回目 | 2529297 | 1637113 |
2回目 | 1773775 | 2122828 |
3回目 | 1562873 | 1654173 |
4回目 | 1737851 | 1462252 |
5回目 | 1758509 | 1495925 |
平均 | 1872461 | 1674458.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回目 | 144446 | 145408 |
2回目 | 176494 | 134025 |
3回目 | 144433 | 156209 |
4回目 | 144435 | 145725 |
5回目 | 140681 | 148039 |
平均 | 150097.8 | 145881.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回目 | 144446 | 199079 |
2回目 | 176494 | 127925 |
3回目 | 144433 | 134707 |
4回目 | 144435 | 154453 |
5回目 | 140681 | 131353 |
平均 | 150097.8 | 149503.4 |
こちらもほんの少しですが、ループ外でサイズを取得した方が速い結果になりました。
ですが速度が不安定なので、配列の場合はわざわざループ外で取得しなくてもいいのかも。
まとめ
全ての場合において拡張for文が最速なのかと思っていましたが、どうやら違ったようですね。
どれが速いのか迷った時は、とりあえずループ外でサイズを取得するfor文にしておけば良さそうです。
まぁ後々になってリストサイズやループ回数が必要になってくる場合があるので、拡張for文を使わない方が無難なのかもしれません。
ArrayListを使う場合
for文(サイズ取得はループ外) < for文 < 拡張for文
配列を使う場合
拡張for文 < for文(サイズ取得はループ外) < for文
コメント