【问题标题】:Condensing down multiple IF statements压缩多个 IF 语句
【发布时间】:2016-04-26 20:36:10
【问题描述】:

我对 Java 还很陌生,我正在尝试制作一个允许我输入一个月,然后输入一天的程序。如果月内的一天有效(即 2 月 28 日有效,29 日无效),我希望它结束​​。我已经让它工作了,但是我每个月都使用了 12 条 IF 语句,它看起来太乱了,而且像太多的代码。 任何人都可以提出一种更好的浓缩方法吗?

import java.util.Scanner;

public class Calender {

public static void main(String[] args) {

int month=0;
int day=0;

Scanner in = new Scanner (System.in);

do {        
System.out.print("Enter a month [1..12]: ");
month=in.nextInt();
//continue;
} while (month > 12);
    //System.out.println ("This is not a valid month.");

do {
System.out.print("Enter a day [1..31]: ");
day=in.nextInt();
} while (day > 31);


if (day > 31 && month == 1) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 31 && month == 3) {
    System.out.print("This is not a valid day of the month");
}
if (day > 31 && month == 5) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 31 && month == 7) {
    System.out.print("This is not a valid day of the month");
}
if (day > 31 && month == 8) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 31 && month == 10) {
    System.out.print("This is not a valid day of the month");
}
if (day > 31 && month == 12) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 30 && month == 4) {
    System.out.print("This is not a valid day of the month");
}
if (day > 30 && month == 6) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 30 && month == 9) {
    System.out.print("This is not a valid day of the month");
}
if (day > 30 && month == 11) {
    System.out.print("This is not a valid day of the month");
} 
if (day > 28 && month == 2) {
    System.out.print("This is not a valid day of the month");
}
}
}

【问题讨论】:

  • 抱歉,最后的 IF 语句应该是 '2' 而不是 '4'
  • 您可以编辑您的帖子以纠正您在原始帖子中所犯的错误。
  • 使用一个 int 数组来保存每个月的天数。那么你只需要一个 if 语句,比如:if (day > months[month] || day <= 0)
  • 查找switch-case 语句。
  • 这个问题最好在SE CodeReview提出

标签: java if-statement


【解决方案1】:

惯用的面向对象方法:

忽略这是一个已经处理的幼稚稻草人问题域 通过 JDK 中的类以及 JodaTime 和其他现有的 解决方案,这旨在作为如何消除密集的示例 以及复杂的if/else if/elseswitch 条件。

这实现了Strategy Pattern 的变体,它专门用于替换具有高cyclomatic complexityif/elseif/else 语句。它同样适用于像这样的狭窄域。

此解决方案利用Enums 实现Interfaces 的能力,并在实际Month 枚举实例中提供Predicate 逻辑。使用Predicate 接口而不是自定义isValidDay() 方法还允许与其他人组合或链接Predicate

这消除了所有嘈杂的重复 if/else if/else 语句,同时允许您遵守 DRY Principle

Q34909522.java

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.google.common.base.Predicate;

public class Q34909522
{
    private static enum Month implements Predicate<Integer>
    {
        JANUARY(31),
        FEBRUARY(28),
        MARCH(31),
        APRIL(28),
        MAY(31),
        JUNE(30),
        JULY(31),
        AUGUST(31),
        SEPTEMBER(30),
        OCTOBER(31),
        NOVEMBER(30),
        DECEMBER(31);

        public final int daysInMonth;

        private Month(final int daysInMonth)
        {
            this.daysInMonth = daysInMonth;
        }

        @Override
        public boolean apply(@Nullable final Integer input)
        {
            return input != null && input >= 1 && input <= this.daysInMonth;
        }
    }

    public static void main(@Nonnull final String[] args)
    {
        /** Scanner excluded for brevity */
        for (final Month m : Month.values())
        {
            for (int i = 0; i <= 33; i++)
            {
                if (!m.apply(i))
                {
                    System.out.format("%d is not a valid day of the month for %s (%d)", i, m, m.daysInMonth );
                    System.out.println();
                }
            }
        }
    }
}

输出:

0 is not a valid day of the month for JANUARY (31)
32 is not a valid day of the month for JANUARY (31)
33 is not a valid day of the month for JANUARY (31)
0 is not a valid day of the month for FEBRUARY (28)
29 is not a valid day of the month for FEBRUARY (28)
30 is not a valid day of the month for FEBRUARY (28)
31 is not a valid day of the month for FEBRUARY (28)
32 is not a valid day of the month for FEBRUARY (28)
33 is not a valid day of the month for FEBRUARY (28)
truncated for brevity ...

闰年:

增强此功能以确定February 是否为闰年 为读者提供练习,因为这是一个有据可查的微不足道的练习 问题和超出规定的要求范围 问题,具体说明 28 in February 是有效的, 29 无效

【讨论】:

    【解决方案2】:

    Java 核心库已经进行了日期解析。

    直接通过 SimpleDateFormat 提供文本输入,并将 lenient 设置为 false。它将为所有无效值抛出异常。

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy MM dd");
    sdf.setLenient(false);
    try
    {
        sdf.parse("2016 " + args[0] + " " + args[1]);
    }
    ....
    

    除了不重新发明轮子之外,这还迫使您明确选择年份,这对闰年日期的合法性有重大影响。

    【讨论】:

      【解决方案3】:

      首先,创建一个包含每个月天数的数组。

      int[ ] daysInMonth = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
      

      然后,将day的值与数组中对应的位置进行比较:

      if (day > daysInMonth[month]) {
          System.out.print("This is not a valid day of the month");
      }
      

      剩下的唯一额外检查是检查二月是否是闰年:

      boolean isLeapYear = (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))
      

      【讨论】:

      • 如果是这样的话,我想你不必担心。系统将检测到连续的否决票并将其删除。到明天一切都应该恢复正常。如果没有,您可以标记以提请版主注意,版主可能会向连续投票者发出警告。
      • @user3437460 :我如何准确地报告/标记连续投票?
      • 标记您怀疑被连续否决的任何帖子以引起版主的注意。您可以选择“需要版主注意”并在文本框中填写说明。
      • @user3437460:谢谢。我试试看!
      • 感谢@JohnSlegers。我很好奇是否有办法让数组从 1 而不是 0 开始?我可以将月份更改为 0-11,但理想情况下我想要 1-12。
      【解决方案4】:

      你可以在这里做很多事情,但我想不到这里有几件事......

      1) 您只有 3 个不同的案例 - 28 天、30 天和 31 天,因此您可以将它们折叠成 3 个 if 语句,如下所示:

      if (day > 30 && (month == 4 || month == 6 || month == 9 || month == 11) {
          ...
      } 
      

      2) 将值存储在数组中并进行查找:

      int[] daysInMonth = new int[] { 31, 28, 31, etc... };
      if (day > daysInMonth[month]) {
          ....
      }
      

      3) 使用内置的时间/日期函数为您处理。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-06
        • 1970-01-01
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 1970-01-01
        • 2018-12-30
        相关资源
        最近更新 更多