Java-код для расчета високосного года - PullRequest
34 голосов
/ 20 июня 2009

Я слежу за книгой "Искусство и наука о Java", и она показывает, как рассчитать високосный год. В книге используется библиотека ACM Java Task Force.

Вот код, используемый книгами:

import acm.program.*;

public class LeapYear extends ConsoleProgram {
    public void run()
    {

        println("This program calculates leap year.");
        int year = readInt("Enter the year: ");     

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

        if (isLeapYear)
        {
            println(year + " is a leap year.");
        } else
            println(year + " is not a leap year.");
    }

}

Вот как я рассчитал високосный год.

import acm.program.*;

public class LeapYear extends ConsoleProgram {
    public void run()
    {

        println("This program calculates leap year.");
        int year = readInt("Enter the year: ");

        if ((year % 4 == 0) && year % 100 != 0)
        {
            println(year + " is a leap year.");
        }
        else if ((year % 4 == 0) && (year % 100 == 0) && (year % 400 == 0))
        {
            println(year + " is a leap year.");
        }
        else
        {
            println(year + " is not a leap year.");
        }
    }
}

Что-то не так с моим кодом или я должен использовать тот, который указан в книге?

EDIT :: Оба вышеприведенных кода работают нормально. Я хочу спросить, какой код является лучшим способом для расчета високосного года

Ответы [ 21 ]

79 голосов
/ 20 июня 2009

Правильная реализация:

public static boolean isLeapYear(int year) {
  Calendar cal = Calendar.getInstance();
  cal.set(Calendar.YEAR, year);
  return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
}

Но если вы собираетесь заново изобрести это колесо, то:

public static boolean isLeapYear(int year) {
  if (year % 4 != 0) {
    return false;
  } else if (year % 400 == 0) {
    return true;
  } else if (year % 100 == 0) {
    return false;
  } else {
    return true;
  }
}
24 голосов
/ 20 июня 2009

Я предлагаю вам вставить этот код в метод и создать модульный тест.

public static boolean isLeapYear(int year) {
    assert year >= 1583; // not valid before this date.
    return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}

В модульном тесте

assertTrue(isLeapYear(2000));
assertTrue(isLeapYear(1904));
assertFalse(isLeapYear(1900));
assertFalse(isLeapYear(1901));
14 голосов
/ 23 мая 2016

java.time.Year::isLeap

Я хотел бы добавить новый java.time способ сделать это с помощью класса Year и isLeap метод:

java.time.Year.of(year).isLeap()
13 голосов
/ 20 июня 2009

Они выглядят одинаково для меня, хотя обратите внимание, что эта строка в вашем коде имеет некоторую избыточность:

else if ((year % 4 == 0) && (year % 100 == 0) && (year % 400 == 0))

можно заменить на:

else if (year % 400 == 0)

Если число кратно 400, то оно автоматически также будет кратно 100 и 4.

редактировать: (7 лет спустя!)

Обратите внимание, что вышеизложенное предполагает наличие предшествующего if ((year % 4 == 0) && year % 100 != 0) из исходного вопроса!

Ответ Клита должен быть принят: https://stackoverflow.com/a/1021373/8331

(я бы удалил свой собственный ответ, но не смогу, поскольку он принят)

8 голосов
/ 17 февраля 2015
new GregorianCalendar().isLeapYear(year);
8 голосов
/ 29 мая 2010

Псевдокод из Википедии переведен на самую компактную Java

(year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))
6 голосов
/ 22 июля 2012

Самый эффективный тест високосного года:

if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0))
{
    /* leap year */
}

Это выдержка из моего подробного ответа на https://stackoverflow.com/a/11595914/733805

5 голосов
/ 01 июня 2016

Из исходного кода JAVA GregorianCalendar:

/**
 * Returns true if {@code year} is a leap year.
 */
public boolean isLeapYear(int year) {
    if (year > changeYear) {
        return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
    }

    return year % 4 == 0;
}

Где changeYear - это год, когда юлианский календарь становится григорианским календарем (1582).

Юлианский календарь определяет високосные годы каждые четыре года, тогда как В григорианском календаре пропущены столетние годы, которые не делятся на 400.

В документации по григорианскому календарю вы можете найти больше информации об этом.

3 голосов
/ 04 марта 2017

Если вы используете java8:

java.time.Year.of(year).isLeap()

Java-реализация вышеуказанного метода:

public static boolean isLeap(long year) {
        return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
    }
3 голосов
/ 20 июня 2009

Почти всегда неправильно иметь повторение в программном обеспечении. В любой инженерной дисциплине форма должна следовать за функцией, и у вас есть три ветви для чего-то, что имеет два возможных пути - високосный год или нет.

Механизм, который имеет тест в одной строке, не имеет этой проблемы, но, как правило, было бы лучше разделить тест на функцию, которая принимает int, представляющий год, и возвращает логическое значение, представляющее, является ли год високосный год. Таким образом, вы можете делать с ним что-то другое, например, выводить на консоль стандартный вывод, и вам будет проще это проверить.

В коде, который, как известно, превышает его бюджет производительности, обычно устраивают тесты так, чтобы они не были избыточными, и выполняли тесты в порядке, который возвращается рано. Пример из Википедии делает это - в течение большинства лет вы должны вычислять по модулю 400, 100 и 4, но для некоторых вам нужно только по модулю 400 или 400 и 100. Это небольшая оптимизация с точки зрения производительности (в лучшем случае, только один из ста вводится), но это также означает, что в коде меньше повторений, и программисту приходится меньше печатать.

...