为什么很多程序员不用 switch,而是大量的 if...else if ...?

编码习惯

我首先来说一下编码习惯,先不说其它的,单从代码行数来看的话,实现相同的逻辑,switchif...else if占用的行数是要多一些的,请看下面的示例代码:

switch版

public class Demo1 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < 10000000; i++) {
            b = i % 10;
            switch (b) {
                case 1:
                    a = a + 2;
                    break;
                case 2:
                    a = a + 3;
                    break;
                case 3:
                    a = a + 4;
                    break;
                case 4:
                    a = a + 5;
                    break;
                case 5:
                    a = a + 6;
                    break;
                case 6:
                    a = a + 7;
                    break;
                case 7:
                    a = a + 8;
                    break;
                case 8:
                    a = a + 9;
                    break;
                case 9:
                    a = a + 10;
                    break;
            }
        }
        e = System.nanoTime();
        System.out.printf("运行时间:%.2f毫秒", (e - s) / 1000000f);
    }
}

if ... eles if 版

public class Demo2 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < 10000000; i++) {
            b = i % 10;
            if (b == 1) {
                a = a + 2;
            } else if (b == 2) {
                a = a + 3;
            } else if (b == 3) {
                a = a + 4;
            } else if (b == 4) {
                a = a + 5;
            } else if (b == 5) {
                a = a + 6;
            } else if (b == 6) {
                a = a + 7;
            } else if (b == 7) {
                a = a + 8;
            } else if (b == 8) {
                a = a + 9;
            } else if (b == 9) {
                a = a + 10;
            }
        }
        e = System.nanoTime();
        System.out.printf("运行时间:%.2f毫秒", (e - s) / 1000000f);
    }
}

上面两个示例类Demo1Demo2实现的逻辑一模一样,Demo1使用switch实现,代码总行数是40行;而Demo2使用if ... else if 实现,总共只有30行(这里显示不了行号,你可以把代码复制到自己的编辑器去看)。

单从这点来看,if ... else if就完胜了 ,毕竟程序员每多敲一个字母,对他手的伤害就会大一些,程序员的手还有其它很重要的用途的 !所以...新手程序员们要保护好自己的手哈。

一个程序员老手的手。。。

说到新手,这里就不得不提使用switch的一个坑了,一般新手都会犯这样的错误,就是忘记写break、忘记写break、忘记写break,这个问题我见过90%的新手都会遇到,break不写编译不会报错,因为在语法上来说,不写也是对的,只是写于不写,所表达的意思不一样。

既然语法是对的,编译当然能通过。因为编译主要就是检测程序的语法是否合格,合格就将源码转换成机器可以执行的代码。所以这也是为什么不写break,还能编译通过的原因。

但程序在执行时,有break和没有break,结果会完全不一样,就拿上面Demo1的例子来说,少了一个break,变量a的结果都会有变化。所以,对于新手来说,switch中的break就是一个隐藏的炸弹,没用好就会产生bug。

但如果你的编程水平高,能彻底明白有break和没有break的区别,那在某些场景还是挺有用的,再来看下面的示例代码:

switch 版:

import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) {
        System.out.print("请输入你的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.next();
        switch (name) {
            case "张三":
            case "李四":
                System.out.println("欢迎你");
                break;
            case "王五":
                System.out.println("对不起,这里不欢迎你");
                break;
            default:
                System.out.println("你叫啥?");
                break;
        }
    }
}

if ... else if 版

import java.util.Scanner;

public class Demo4 {
    public static void main(String[] args) {
        System.out.print("请输入你的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.next();
        if ("张三".equals(name) || "李四".equals(name)) {
            System.out.println("欢迎你");
        } else if ("王五".equals(name)) {
            System.out.println("对不起,这里不欢迎你");
        } else {
            System.out.println("你叫啥?");
        }
    }
}

这个示例的逻辑很简单,在控制台输入姓名,然后如果是张三或李四,就打印欢迎你,对王五打印不欢迎的内容。

这里如果仅从代码行数去看的话,还是使用if ... else if占优势,但从代码的可阅读性和可扩展性来说的话,明显使用switch更合适。

为什么这么说?举个栗子,业务上现在是要求对张三和李四说欢迎,如果隔壁的产品经理哪天想给你找点事干,要求对赵一、赵二、赵三等等都说欢迎,那在Demo4里面得不断往if的条件后再追加条件;而在switch版本里面只需要追加一个case,而且看上去还一目了然,结构非常清晰,示例如下:

import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) {
        System.out.print("请输入你的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.next();
        switch (name) {
            case "赵一": // 追加的需求
            case "张三":
            case "李四":
                System.out.println("欢迎你");
                break;
            case "王五":
                System.out.println("对不起,这里不欢迎你");
                break;
            default:
                System.out.println("你叫啥?");
                break;
        }
    }
}

另外,在某些场景使用switch也会增加程序的复杂性和可读性。就拿上面的Demo1的代码来说,如果想要在switchcase 1里面跳出当前的for循环,那该怎样做呢?

public class Demo1 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < 10000000; i++) {
            b = i % 10;
            switch (b) {
                case 1:
                    a = a + 2;
                    // 在此次如何跳出for循环???
                    break;
                case 2:
                // 此处省略诺干行......
            }
        }
    }
}

大家知道for循环中要跳出当前的for循环,也是使用break关键字,但此处是在switch里面,switch里的break是退出当前的case。所以。。。 对于小白来说,这里就懵了!

真的,一般人还真不知道怎样处理这个问题,有人会想到立一个flag,在switch结束后去判断这个flag,或者直接判读i的值,比如下面这样:

public class Demo1 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < 10000000; i++) {
            b = i % 10;
            switch (b) {
                case 1:
                    a = a + 2;
                    break;
                case 2:
                // 此处省略诺干行......
            }
            // 在此处判断,满足条件就跳出循环
            if (i == 0) {
                break;
            }
        }
    }
}

还有人可能会用到Java中的标签语法,就像这样:

public class Demo1 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        LABEL_FOR:// 给此处的for循环定义一个标签
        for (int i = 0; i < 10000000; i++) {
            b = i % 10;
            switch (b) {
                case 1:
                    a = a + 2;
                    break LABEL_FOR; // 跳出for循环
                case 2:
                // 此处省略诺干行......
            }
        }
    }
}

这种方法一般人也想不到,因为很少有人这样写,有人写了四五年的代码都不一定见过,但这的确是Java中支持的语法。

虽然这样比上面的判断方法看上去优雅,但增加了程序的复杂性和可读性。如果使用的是if else if,根本不用搞这么复杂,直接使用break即可,就像这样:

public class Demo2 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            b = i % 10;
            if (b == 1) {
                a = a + 2;
                break; // 此处的break可以直接跳出当前for循环
            } else if (b == 2) {
                // 此处省略诺干行......

所以,从编码风格来说的话,需要结合实际的业务需求去选择使用哪种语法。

程序性能

从性能上来说的话,如果不是做大量的运算的话,性能上是几乎没有差异的。

就拿上面的Demo1Demo2来说的话,两个程序运行耗时都是差不多。

但如果把for循环的次数加大几倍,其结果就明显了,看下面的示例和结果:

switch 版

public class Demo1 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            b = i % 10;
            switch (b) {
                case 1:
                    a = a + 2;
                    break;
                case 2:
                    a = a + 3;
                    break;
                case 3:
                    a = a + 4;
                    break;
                case 4:
                    a = a + 5;
                    break;
                case 5:
                    a = a + 6;
                    break;
                case 6:
                    a = a + 7;
                    break;
                case 7:
                    a = a + 8;
                    break;
                case 8:
                    a = a + 9;
                    break;
                case 9:
                    a = a + 10;
                    break;
            }
        }
        e = System.nanoTime();
        System.out.printf("运行时间:%.2f毫秒", (e - s) / 1000000f);
    }
}

if ... else if 版

public class Demo2 {
    public static void main(String[] args) {
        long s = System.nanoTime(), e;
        int a = 0, b;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            b = i % 10;
            if (b == 1) {
                a = a + 2;
            } else if (b == 2) {
                a = a + 3;
            } else if (b == 3) {
                a = a + 4;
            } else if (b == 4) {
                a = a + 5;
            } else if (b == 5) {
                a = a + 6;
            } else if (b == 6) {
                a = a + 7;
            } else if (b == 7) {
                a = a + 8;
            } else if (b == 8) {
                a = a + 9;
            } else if (b == 9) {
                a = a + 10;
            }
        }
        e = System.nanoTime();
        System.out.printf("运行时间:%.2f毫秒", (e - s) / 1000000f);
    }
}

以上代码中,将for循环的次数改为了Integer.MAX_VALUE。再来看一下两个程序运行的结果:

先贴上我的机器配置:

我的高性能本子
说明:不同的机器配置,运行耗时会不一样。

Demo1运行3次的结果

运行时间:4464.96毫秒
运行时间:4501.70毫秒
运行时间:4660.67毫秒

Demo2运行3次的结果

运行时间:5892.39毫秒
运行时间:6014.14毫秒
运行时间:5440.15毫秒

通过对比会发现,在做大量运算时,switch的性能更优。

所以,如果你看过一些框架的源码就会发现那些作者他们很多地方都用的是switch,就是这个原因。

小结

  • 从编码习惯上来说,switchif ... else if各有利弊,需要结合实际的业务需求去选择使用哪种语法。
  • 如果程序性能上说的话,一般的程序中使用switchif ... else if几乎没有差异,只有在需要做大量的运算,switch的优势才能体现。
  • 参考文本
    学习视频资料:http://www.makeru.com.cn/live/1392_1164.html?s=143793

posted @ 2020-12-02 16:24  欧清辣哨  阅读(321)  评论(0编辑  收藏  举报