状況
前回記事(なぜelse、else ifを書かないようにすべきなのか?)のような
ifのみで判定されており、それがfor文等の繰り返し処理の中にある場合は
パフォーマンスが下がる。
対処法
メソッドを切り出し、早期リターンとする。
10億回のfor文でパフォーマンス評価
else有り、else無しで評価してみた。
(測定単位:ミリ秒)
else 有り
1 2 3 4 5 6 7 8 9 10 11 12 |
for(long i = 0; i < 1000000000; i++) { if(sex.equals("man")) { sexStr = "男性"; }else if(sex.equals("woman")){ sexStr = "女性"; }else if(sex.equals("other")){ sexStr = "その他"; }else { sexStr = "未設定"; } } // ※全コードは最後に掲載 |
if文条件に当てはまれば、その時点で判定は終了するため、
より最初の方(上記の場合は、”man”)であるほど、判定は速く終了する。
<結果>
man :344
woman :343
other :2250
(未設定):1953
else 無し
1 2 3 4 5 6 7 |
for(long i = 0; i < 1000000000; i++) { sexStr = "未設定"; if(sex.equals("man")) sexStr = "男性"; if(sex.equals("woman")) sexStr = "女性"; if(sex.equals("other")) sexStr = "その他"; } // ※全コードは最後に掲載 |
全てのif文を判定するため、必ず一定の処理時間がかかる。
<結果>
man :1938
woman :2219
other :2212
(未設定):1898
結果(else無しは一定して遅い)
man、womanはelse有りの方が速い。
理由は、if文条件に合致したあとの後続処理(otheのif文等)は行われないため。
else無しの場合は、すべてのif文を実行するので処理が遅くなる。
上記の結果から、else有りと同じロジックに修正することで改善を試みる。
方法として、else無しをメソッドに切出して早期リターンとする。
パフォーマンス改善
else 無し AND メソッド切り出しして早期リターン
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
for(long i = 0; i < 1000000000; i++) { sexStr = sexStr(sex); } /** * sexを日本語の性別に変換 * @param sex * @return sexStr */ public static String sexStr(String sex) { if(sex.equals("man")) return "男性"; if(sex.equals("woman")) return "女性"; if(sex.equals("other")) return "その他"; return "未設定"; } // ※全コードは最後に掲載 |
if文条件に当てはまれば判定結果をリターンするようにしたため、
後続のif文判定が行われない。
<結果>
man :321
woman :320
other :2199
(未設定):1863
結果(最速になった)
単位(ミリ秒) | man(男性) | woman(女性) | other(その他) | ""(未設定) |
---|---|---|---|---|
else有り | 344 | 343 | 2250 | 1953 |
else無し | 1938 | 2219 | 2212 | 1898 |
else無し (早期リターン) | 321 | 320 | 2199 | 1863 |
全3パターンで最速になりました。
else有りよりもわずかに早くなっているのは、「else」自体の処理が無いためと推察しています。
まとめ
・else有りだと、判定条件の順番によっては速く処理される。
・else無しだと、すべての判定を行うため、一律に処理時間がかかる。
・メソッドに切り出して早期リターンとすると、else有りと同等の処理速度をelse無しで実現できる。
コード全体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class NotElse { public static void main(String...strings) { String sex = "man"; String sexStr = ""; System.out.println("sex : " + sex); // Before: else句を使用した場合 long b_start = System.currentTimeMillis(); for(long i = 0; i < 1000000000; i++) { if(sex.equals("man")) { sexStr = "男性"; }else if(sex.equals("woman")){ sexStr = "女性"; }else if(sex.equals("other")){ sexStr = "その他"; }else { sexStr = "未設定"; } } System.out.println(sexStr); long b_end = System.currentTimeMillis(); System.out.println("else 有り(milli sec) : " + (b_end - b_start)); // After: else句を使用しない場合 long a_start = System.currentTimeMillis(); for(long i = 0; i < 1000000000; i++) { sexStr = "未設定"; if(sex.equals("man")) sexStr = "男性"; if(sex.equals("woman")) sexStr = "女性"; if(sex.equals("other")) sexStr = "その他"; } long a_end = System.currentTimeMillis(); System.out.println("else 無し(milli sec) : " + (a_end - a_start)); // After and Refactoring: メソッド切り出しした場合 long ar_start = System.currentTimeMillis(); for(long i = 0; i < 1000000000; i++) { sexStr = sexStr(sex); } long ar_end = System.currentTimeMillis(); System.out.println("else 無し[メソッド切り出し](milli sec) : " + (ar_end - ar_start)); } /** * sexを日本語の性別に変換 * @param sex * @return sexStr */ public static String sexStr(String sex) { if(sex.equals("man")) return "男性"; if(sex.equals("woman")) return "女性"; if(sex.equals("other")) return "その他"; return "未設定"; } } |
コメント