【问题标题】:Question about return statements关于return语句的问题
【发布时间】:2010-12-09 21:12:06
【问题描述】:
import java.util.Scanner;

public class GregorianYear

{
    private int year;

    public GregorianYear(int a)

    {
        year = a;
    }

    public void SetYear()
        {
        System.out.println( "The year is: " );
        Scanner kbd = new Scanner( System.in );
            year = kbd.nextInt();
    }

    public int getYear()
    {
        return year;
    }

    public boolean isLeapYear()
    {
        if ( year > 1852 )
        {
            if ( year % 100 == 0)
            {
                if ( year % 400 == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
    //Compiler says I need a return statement here.
    }
}

我正在编写一个(应该是)简单的类程序,当我没有任何东西时,它说我需要一个返回语句。我假设我只能返回一个布尔语句,所以我输入 return isLeapYear();。当我这样做时,我的测试方法(另一个具有公共静态 void main 的文件)运行并在我输入 return 语句的行导致 StackOverflow 错误。我做错了什么?

【问题讨论】:

  • 选择更易读的缩进样式 (en.wikipedia.org/wiki/Indent_style)。另外,请发布测试代码;您发布的代码没有任何会导致堆栈溢出的内容。为什么要歧视 1852 年之前的年份?
  • 注意:方法名以小写字符开头。
  • 由于一些并发编辑,缩进搞砸了,我现在稍微修复了它。是的,这种缩进很可怕,但我可以看到它在学校里教,所以我并不是真的在抱怨,我只是希望乔伊能在某个时候看到正确缩进的光芒。
  • 我认为 1852 应该读作 1582,这是许多天主教国家采用公历的年份。美国独立后采用公历。它是追溯采用的,这意味着几个世纪在美国有两个日期,我们现在称之为的那一天和那天被调用的那一天。因此,如果您阅读独立前的文件,您可能会阅读自编写以来已更改的日期。 ;)

标签: java algorithm return


【解决方案1】:

编译器是正确的,你的方法的结构方式意味着在它的最后有一个额外的分支路径需要处理,在这种情况下,它是 if ( year > 1852 ) 的不可见的 else 分支。如果再次调用相同的方法,实际上只是将其再次指向相同的 else 分支,因为调用之间的年份不会改变,这会导致无限递归。

您真正想要的答案是“1852 年之前的任何一年是否是闰年?”,但是因为这个问题实际上不是原子的(公历日历从 2 月 24 日开始1582)你甚至有一个错误,所以在修复它之后你可以放心地说不,在那之前的任何年份都不能是闰年。 p>

【讨论】:

    【解决方案2】:

    基本上如果你的方法声明了一个返回值,那么你在这个方法中的所有代码路径都必须返回一些东西,对于你发布的代码,如果 year 怎么办?这种情况下的返回值应该是多少??

    【讨论】:

      【解决方案3】:

      如果您再次调用 isLeapYear,它将永远运行。但要使用正确的标识。

      if ( year > 1852 )
      {
         if ( year % 100 == 0)
         {
            if ( year % 400 == 0)
            {
               return false;
            }
            else
            {
               return true;
            }
         }
      }
      

      如您所见,您没有针对 if (year > 1852) 和 if (year %100 == 0) 的 else 语句,因此编译器无法确定返回的值。

      【讨论】:

        【解决方案4】:

        您需要为每个代码路径返回一个值,包括年份早于 1853 年的路径。在您的代码中,没有考虑这种情况。

        以下功能将按您的意愿工作。我假设您实际上是指1582,因为那是开始使用公历的那一年(无论如何,在天主教世界中)。由于它是在当年 10 月颁布的,尽管符合 4/100/400 规则,1582 年本身并不是闰年。

        我已将代码重新格式化为我认为更具可读性的样式 - 我不是 returns 和 elses 的忠实粉丝,因为它们在我看来破坏了含义(其他人可能不同意,但我相信这种形式更容易发现缩进问题)。而且,最重要的是,您似乎根本没有考虑每四年一次的规则。

        public boolean isLeapYear() {
            // No leap years before Greg the Pope.
        
            if ( year < 1583 )
                return false;
        
            // Multiples of 400 are leap years.
        
            if ( year % 400 == 0)
                return true;
        
            // Multiples of 100 (other than multiples of 400) are not.
        
            if ( year % 100 == 0)
                return false;
        
            // Multiples of 4 are, assuming they're not multiples of 100.
        
            if ( year % 4 == 0)
                return true;
        
            // All other aren't.
        
            return false;
        }
        

        当然,理想的解决方案可能只是使用GregorianCalendar.isLeapYear(int year),记录在here。由于 Java 类库提供了大量有用的东西,你很少需要编写这样一段基本的代码(除了家庭作业)。

        整个课程的所有优点(包括更改儒略-格里高利转换日期的能力)都记录在 here

        【讨论】:

          【解决方案5】:

          当然,在外部 if 之后需要一个 return 语句。因为年份可以是&lt;= 1852

          如果您的方法应该只处理 1852 年之后的年份,您可以改为抛出异常。

          【讨论】:

            【解决方案6】:

            提示:如果您在 isLeapYear() 方法的主体中使用 return isLeapYear();,您是在告诉它递归调用自身。

            提示 2:修正代码的缩进,你会更容易理解它的问题所在。

            【讨论】:

              【解决方案7】:

              当你写“return IsLeapYear()”时,你会导致一个无限循环。 由于您不关心 1852 年之前的年份,因此只需返回 true 或 false 并获得 A-...

              【讨论】:

                【解决方案8】:

                您必须添加return false;。因为该方法需要返回一个值(布尔值)。 如果您在 if 中的第一个条件不正确,则所有内容都将被跳过。 您的第一个条件检查year&lt;=1852。现在想象一下:如果你的年份是&lt;= 1852,他会返回什么。

                【讨论】:

                  【解决方案9】:

                  调用你自己的方法而不改变参数,如果确定方法进入无限递归,再次调用你的方法直到堆栈空间用完。

                  您询问 return 语句,这就是您可以改进代码并修复递归的地方。

                  作为一项规则,尽量只有一个 return 语句。在这种情况下这样做会导致:

                  public boolean isLeapYear()
                  {
                      boolean result = false;
                      if ( year > 1852 )
                      {
                              if ( year % 100 == 0)
                              {
                                      if ( year % 400 != 0)
                                      {
                                              result = true;
                                      }
                              }
                      }
                      return result;
                  }
                  

                  顺便说一句,我似乎记得闰年也与 4 的倍数有关 :-)

                  【讨论】:

                  • 对我来说,与其说是规则不如说是指导。特别是如果多返回版本在不牺牲理解所有代码路径的能力的情况下有助于可读性 - 使用这么小的函数,它应该很容易(尽管不可否认,对于更大的函数来说并非如此)。
                  • 你是对的,我的规则是指所有没有充分理由不这样做的情况的指南。对于像这样的函数 1 return 对我来说更具可读性。
                  【解决方案10】:

                  在公历之前使用的儒略历的闰年规则是每四年为闰年。 公历保留了这一规则,只是添加了完整世纪和 400 年的倍数的特殊规则。

                  您的代码只计算了例外规则,但错过了基本规则(除了缺少的 return 语句)。

                  【讨论】:

                    猜你喜欢
                    • 2020-07-18
                    • 1970-01-01
                    • 2010-09-24
                    • 2013-06-14
                    • 1970-01-01
                    • 2018-10-28
                    • 1970-01-01
                    • 2015-08-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多