21
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ifとswitchどっちがいいのか問題

Last updated at Posted at 2019-04-03

はじめに

  • みなさんコーディングをしてきて、今までに何回ifを書いてきましたか?笑
  • 何万回と書いていても、たまにswitchを使うかifを使うか悩みますよね??(僕は悩むことがあります)

今の僕の選択基準

  • if文を選ぶとき:&&とか||したいとき
  • switchするとき:選択肢がいっぱいあるとき
  • switchするまでもないとき:三項演算子
  • あとは悩んだら感覚
  • てな感じで選んでたわけなんですが、ある日僕は思いました

どっちでもかけるときってどっちがパフォーマンス出るんだろう?

  • 気になったら計測すればいいんじゃね?と思い立ちます
  • いざ、実行!

用意したもの

  • Java1.8
  • IntelliJ IDEA

目次(目次を書いてる時点でやる想定のもの)

  • 100回くらいのループで分岐を走らせる
  • 100回で性能差が出なかったら、桁数を1つずつ増やしていく
  • ある程度満足したら、条件を増やしていく
  • 条件増やすのにも満足したら、文字列と数字のパターンをやる
  • こんな感じでやります

実践

100回くらいのループで分岐を走らせる

  • 実行したコードは下記
CheckPerformance.java
import java.util.stream.IntStream;

public class CheckPerformance {

    public static void main(String[] args) {
        Long start = System.currentTimeMillis();
        // if実行分
        IntStream.rangeClosed(0, 100).forEach(i -> {
            if (i % 2 == 0) {
                System.out.println("偶数です");
            } else if (i % 2 == 1) {
                System.out.println("奇数です");
            } else {
                System.out.println("その他です");
            }
        });

        // switch実行分
        IntStream.rangeClosed(0, 100).forEach(i -> {
            switch (i % 2) {
                case 0:
                    System.out.println("偶数です");
                    break;
                case 1:
                    System.out.println("奇数です");
                    break;
                default:
                    System.out.println("その他です");
                    break;
            }
        });
        Long end = System.currentTimeMillis();
        System.out.println(end - start + "ms");
    }
}
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 7ms 12ms
2回目 15ms 10ms
3回目 13ms 12ms
4回目 8ms 15ms
5回目 10ms 10ms

検証

  • 他にも何回か実行したが、運ゲーみたいになったので100回では性能差を検証するのは難しいと判断
  • 要するに誤差でしかない

1,000回のループで分岐を走らせる

  • ソースは省略
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 36ms 39ms
2回目 33ms 35ms
3回目 31ms 28ms
4回目 38ms 39ms
5回目 38ms 34ms

検証

  • うーん、1,000回でも性能差を検証するのは微妙
  • ここでもまだ、誤差の範疇な気がする

10,000回のループで分岐を走らせる

  • ソースは(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 133ms 119ms
2回目 147ms 136ms
3回目 116ms 121ms
4回目 135ms 130ms
5回目 128ms 136ms

検証

  • うーん、10,000回でも...(ry

100,000回のループで分岐を走らせる

  • ソースは(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 903ms 917ms
2回目 947ms 885ms
3回目 1012ms 964ms
4回目 1109ms 947ms
5回目 943ms 884ms

検証

  • 100,000回でちょっとだけ性能差がでた気がします
  • switchが1秒超えたのが0回だったのに対して、ifは2回ありますね。
  • とはいえ、誤差っちゃ誤差なのかもしれないし、平均値だけみるとswitchの方が早いのかも?って仮説はたちました
  • でも、ちょっと不安なのでもう1桁だけ増やして実行しておきます

1,000,000回のループで分岐を走らせる

  • s..(ry
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6366ms 6339ms
2回目 6410ms 6396ms
3回目 6794ms 6298ms
4回目 6730ms 6248ms
5回目 6823ms 6495ms

検証

  • 1,000,000回での性能差はご覧の通りです
  • switchの方が速度にばらつきが無かった気がするのと、やっぱり若干ですが早いという結果に
  • とはいえ、100万件やってようやくこれだけしか性能差が出ないんで、普段使いで性能差を意識することはなかなかなさそうですかね

分岐を増やしていく

  • では、ある程度満足したので分岐を増やしていきます
  • ここからは100件でやってもあまり意味がないことがわかったので100万件で実施していきます

まずは分岐を3つにする

  • ソースは省略します
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6348ms 6476ms
2回目 6751ms 6354ms
3回目 6461ms 6324ms
4回目 6500ms 6411ms
5回目 6537ms 6646ms

検証

  • 分岐3回での性能差はご覧の通りです
  • 平均値でみたときにはswitchの方が、やっぱり若干ですが早いですかね
  • とはいえ、誤差なのかもしれないので分岐を増やします

分岐を5つにする

  • 5つにしたのは計算の都合上と気分です
  • 実行結果は下記です
X回目 ifの実行秒数 switchの実行秒数
1回目 6528ms 6279ms
2回目 6452ms 6507ms
3回目 6661ms 6599ms
4回目 6501ms 6589ms
5回目 6608ms 6322ms

検証

  • 分岐5回での性能差はご覧の通りです
  • うーん誤差の範囲内ですかね。

結論

ifとswitchは性能差はほとんどない!

  • タイトルで釣っておいてあれなんですが、僕なりの結論です
  • 100万件しか実行してないのですが、もっと増えれば変わる可能性はあるかもなのは重々承知してます
  • とはいえ、分岐の数や処理件数でifとswitchでパフォーマンスが顕著に変わることはないっぽいので、その時々に合わせて読みやすくなる実装を選択するという判断が正しい気がします
  • 何かおかしいだろとか、もっとこんな検証した方がいい等々あればコメントでも編集リクエストでもください!

追記

  • コメントにてprintlnが重すぎるのでというご指摘をいただいたので、処理を直してみました
Main.java
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

public class Main {

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

        IntStream.rangeClosed(0, 10000000).forEach(
                num -> {
                    if (num % 2 == 0) {
                        int num2 = 2;
                    } else if (num % 2 == 1){
                        int num3 = 2;
                    } else {
                        int num4 = 2;
                    }
                }
        );
        IntStream.rangeClosed(0, 10000000).forEach(
                num -> {
                    switch (num % 2) {
                        case 0:
                            int num2 = 2;
                            break;
                        case 1:
                            int num3 = 2;
                            break;
                        default:
                            int num4 = 2;
                            break;
                    }
                }
                        );
        long end = System.currentTimeMillis();
        System.out.println((end - start)  + "ms");

    }
}

  • I/Oの処理が重いのでとりあえずfor文の中で変数宣言するだけにしてみました
  • もっといけてる方法あったらおしえてください

実行結果

X回目 ifの実行秒数 switchの実行秒数
1回目 79ms 70ms
2回目 81ms 64ms
3回目 90ms 62ms
4回目 86ms 67ms
5回目 83ms 63ms
  • 1000万件回して差分が20msくらいは性能差が出ましたが、やはりほとんどないという結論で問題ないのかと。
  • byteコードの検証は後日します!
21
6
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?