Switch穿透的一点使用,将“缺点”转换为“优点”

碰到一个题目,输入某年某月某日,判断这一天是这一年的第几天? 不使用时间日期相关的API或者数组啥的,只用判断语句和循环语句实现。

一开始我的想法自然而然是用if语句来暴力实现:

if (month == 12) {
    将天数加 31 + 30 + 31 +...31。 把之前十一个月的天数都加起来
} else if (month == 11) {
    将天数加 30 + 31 + 30...31。 把之前十个月的天数都加起来
} else if...

这样固然可以实现将月份的天数全部加起来,但是感觉特别繁琐,然后我又想着是否能通过其他的方式来简化流程,自然而然想到了switch,但是脑袋里又下意识的否决了这个想法。因为在我的认知里,if语句比switch语句要好太多,两者的异同早已背的滚瓜烂熟:

  1. 两者都是用来处理多分支条件的结构
  2. switch用于等值条件判断,条件是有限个的时候。
  3. 可判断某个连续区间的条件。
  4. if语句每个条件都会进行判断,switch性能效率会比较高一点。

这些异同,我感觉switch就是效率会比较高这一个优点,并且这个优点我也觉得不是特别重要,那点效率又有啥用呢,又何必为了这一点点效率而放弃用起来舒服数倍的if呢。

就在我准备专用循环来解决问题的时候,脑袋里突然闪过switch的还有一个东西,是if语句没有的,那就是穿透。 if语句每个分支不需要加break,运行完自然而然就会跳出if语句,而switch每个分支需要加break才能跳出,否则会出现穿透情况。 每个视频或者每本书讲到switch时,都会千叮咛万嘱咐不要忘记加break,不然代码逻辑就会出错。这一点让本来就不喜欢switch的我更加讨厌它了。

然而,当前这个题目的代码逻辑,让我察觉到if的一些局限了。于是,我决定先不用循环,先开始尝试用switch来优化代码:

switch(month) {
    case 12: 
        将天数加 31 + 30 + 31 +...31。 把之前十一个月的天数都加起来
        break;
    case 11: 
        将天数加 30 + 31 + 30...31。 把之前十个月的天数都加起来
        break;
    ...
    ...
}

emmm,感觉还是和if没有区别,不过,这个代码其中关键逻辑 或者说 重复的部分就是之前所有月份的天数进行相加:12月就加 11月 和 10月 和 9月...,11月就加 10月 和9 月 和 8月...。 加的天数都是 下一个月的天数和下一个分支条件所需要加的月数。 既然和下一个分之条件的代码有重复,那么穿透在此时岂不正好?

switch(month) {
    case 12: // 如果是12月,就将第11月的天数进行相加
        将天数加 31;
    case 11: // 如果是11月,就将第10月的天数进行相加
        将天数加 30;
    ...
    ...
}

代码逻辑瞬间清晰多了,因为没有在case后面加上break,所以如果月份是12的话,加完11月的天数后,又会继续运行下一步case,将之前的所有月份全部加上。至此,核心逻辑已经比if语句好了太多。 整个功能用switch来实现的完整代码如下:

import java.util.Scanner;

/**
 * 
 * @function 输入某年某月某日,判断这一天是这一年的第几天
 * @author RudeCrab
 * @date 2019年3月27日下午5:35:07
 * @version 1.0.0
 * @copyright RudeCrab
 */
public class Subject2 {

    public static void main(String[] args) {
        // 创建Scanner对象,方便等下录入数据
        Scanner input = new Scanner(System.in);
        // 提示用户输入年份,并录入数据赋值给变量
        System.out.print("请输入年份:");
        int year = input.nextInt();
        // 提示用户输入月份,并录入数据赋值给变量
        System.out.print("请输入月份:");
        int month = input.nextInt();
        // 提示用户输入天数,并录入数据赋值给变量
        System.out.print("请输入天数:");
        int day = input.nextInt();
        // 声明变量,后面用来存放总天数数据
        int dayNum = 0;

        // 进行数值合法判断
        if (month > 13 || month < 1 || year < 1 || day < 1 || day > 31) {
            // 如果不合法则提示用户输入错误
            System.out.println("输入的数字有误!");
            // 程序退出
            System.exit(0);
        }

        // 先判断年份是否为闰年,将结果赋值给变量
        boolean isLeapYear = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;

        // 如果不是闰年 用户输入的是2月29日,则为不合法
        if (!isLeapYear && month == 2 && day > 28) {
            // 如果不合法则提示用户输入错误
            System.out.println("这一年不是闰年,2月只有28天哦!");
            // 系统退出
            System.exit(0);
        }

        // 再判断月份,将大月和小月分开,用switch进行穿透
        switch (month) {
        case 12:// 如果是12月份,则将11月份的天数进行相加
            dayNum += 30;
        case 11:// 如果是11月份,则将10月份的天数进行相加
            dayNum += 31;
        case 10:// 如果是10月份,则将9月份的天数进行相加
            dayNum += 30;
        case 9:// 如果是9月份,则将8月份的天数进行相加
            dayNum += 31;
        case 8:// 如果是8月份,则将7月份的天数进行相加
            dayNum += 31;
        case 7:// 如果是7月份,则6月份的天数进行相加
            dayNum += 30;
        case 6:// 如果是6月份,则将5月份的天数进行相加
            dayNum += 31;
        case 5:// 如果是5月份,则将4月份的天数进行相加
            dayNum += 30;
        case 4:// 如果是4月份,则将3月份的天数进行相加
            dayNum += 31;
        case 3:// 如果是3月份,则将2月份的天数进行相加
                // 判断年份是否为闰年
            if (isLeapYear) {
                dayNum += 29; // 如果是闰年则2月为29天,则加29天
            } else {
                dayNum += 28; // 如果不是闰年则2月为28天,则加28天
            }
        case 2:// 如果是2月份,则将1月份的天数进行相加
            dayNum += 31;

        }

        // 最后将天数加的总天数里
        dayNum += day;
        // 打印信息
        System.out.printf("%d年%d月%d日是这一年的第%d天", year, month, day, dayNum);
        // 关闭input流
        input.close();
    }

}

总结和思考:
经过这次之后,我对switch再也没有偏见,一个代码功能在一个地方如果有缺陷的话,可能并不是功能本身的问题,而是没有放在合适的位置使用!

你可能感兴趣的:(java)