Самый краткий способ определения количества дней в месяце с помощью Java (с использованием логических операторов)

Недавно я получил это задание в моем начальном классе информатики:

Напишите программу, которая просит пользователя ввести месяц (1 = январь, 2 = февраль и т. Д.), А затем печатает количество дней в месяце. Для февраля выведите «28 дней». Введите месяц (1–12): 5 31 день. Реализуйте класс Month с помощью метода int getDays (). Не используйте отдельный оператор if или else для каждого месяца. Используйте логические операторы.

Я не прошу кого-то выполнить указанное задание, а скорее критикую мое собственное решение. Прежде чем спросить об этом, я провел базовый поиск, но в большинстве, если не во всех решениях, используется класс Calendar и таким образом вычисляется количество дней. Цель этого присвоения - передать идею условных операторов и логических операторов.

Мое решение: Season.java

/**
 * @author Jared Holley
 * Date: 4/01/14
 * Period: 3rd
 * 
 * Write a program that asks the user to enter a month (1 = January, 2 = February, and
 * so on) and then prints the number of days of the month. For February, print
 * “28 days”.
 * 
 * With a method int getDays(). Do not use a separate if or else
 * statement for each month. Use Boolean operators.
 */

 //31: 1,3,5,7,8,10,12
 //30: 2,4,6,9,11
 public class Month {
  private int month;

  /**
   * The constructor for the Month class.
   * Simply takes in a monthNumber and sets it to the 
   * class variable.
   * @param monthNumber
   */
  public Month(int monthNumber){
    month = monthNumber;
  }

  /**
   * The method that converts a month number into the number of days within that month.
   * It first checks if the month is February so that it eliminates that from the        following conditions that would produce a false positive.
   * It then goes through and uses a rather odd conditional statement.
   * The first half of the if statements increments all the months by one and checks if they are even.
   * This would turn January into 2 which does have 31 days and trun April into 5 which has 30 days.
   * The second half just checks the even months beyond 7.
   * Lastly it will just return 30 otherwise.
   * @return The numbers of days within the month.
   */
  public int getDays(){
    if(month == 2)return 28;
    if( ((month + 1) % 2 == 0 && month < 9) || ((month % 2 == 0) && month >= 8))   return 31;
    return 30;

  }
}

Решение работает нормально. Я просто хотел бы знать, есть ли более элегантный подход к делу. Мое условное утверждение выглядит очень некрасиво. Спасибо за помощь!


person Holleyj66    schedule 03.04.2014    source источник
comment
Это действительно выглядит плохо, но, учитывая задание, я не уверен, что вы сможете что-то улучшить. Примечание: вы можете сделать month final. Кроме того, month % 2 != 0 может быть яснее, чем _3 _...   -  person assylias    schedule 03.04.2014
comment
Спасибо! Я был почти уверен, что его нельзя сокращать. Тем не менее, я внесу предложенное вами изменение, поскольку мне легче понять мои доводы.   -  person Holleyj66    schedule 03.04.2014
comment
Не делайте month final, если вы не хотите, чтобы этот класс был неизменным. И если вы сделаете month final, это должно быть public final, поскольку это примитив.   -  person Jared    schedule 03.04.2014
comment
@jared Иммутабельность IMO должна быть значением по умолчанию для такого класса значений. Я не уверен, почему вы думаете, что это должно быть публично.   -  person assylias    schedule 03.04.2014
comment
@assylias Почему он не должен быть публичным (если он окончательный)? Это мои рассуждения.   -  person Jared    schedule 03.04.2014
comment
@Jared Лично я, помните, я новичок, и считаю, что решение о том, делать его публичным или приватным, во многом зависит от ситуации. В этом конкретном случае я сохраню его как конфиденциальный, потому что я не планирую получать к нему доступ из любого другого места. Есть ли недостатки в моей теории?   -  person Holleyj66    schedule 03.04.2014
comment
@ Джаред скажем (надуманный пример), что вы понимаете, что getDays метод будет намного лучше return daysArray[month];, но вы действительно не хотите тратить место и решили, что month должен начинаться с индекса 0. Вы только что сломали весь код, который зависел на month - это человеческое представление числа месяца. Использование частной переменной и метода getMonthNumber дает вам гибкость при изменении вашей реализации, если вы хотите, чтобы никто не заметил.   -  person assylias    schedule 03.04.2014
comment
@Jared, потому что подклассы могут переопределять его в конструкторах, когда они общедоступны или защищены   -  person thobens    schedule 03.04.2014
comment
@thobens Нет, попробуй. Подкласс должен вызывать конструктор суперкласса, который, если он final, должен установить значение.   -  person Jared    schedule 03.04.2014
comment
Использование переменной month полностью является ответственностью вызывающего класса за ее правильное использование. Цель объявления вещей частным, защищенным или на уровне пакета - это доверие. Предоставляя доступ к внутренней переменной, вы уверены, что вызывающий класс не может сделать ваш объект несогласованным. Но если это final (и примитивный или неизменяемый объект), то любой другой класс не может нарушить this объект. Но прямое чтение переменных всегда предпочтительнее, чем вызов метода.   -  person Jared    schedule 03.04.2014
comment
Кажется, это лучше подходит для проверки кода.   -  person Azar    schedule 03.04.2014
comment
@ Джаред: ты прав, это примитив. Но опять же, и назовите меня старомодным, какого черта вы тогда определили бы это публично? Это немного из-за того, что я могу относиться к делу, не так ли? Предполагая, что вы реорганизуете код и измените тип переменных month и BAM, у вас есть общедоступная переменная, которая вам не нужна.   -  person thobens    schedule 03.04.2014
comment
@Jared, за исключением того, что все общедоступные члены являются частью api вашего класса: как только другие классы начинают использовать эти члены, вы застреваете. Сохранение их конфиденциальности дает вам большую гибкость. Было бы больно следовать вашим советам по любому проекту, не связанному с игрушками ...   -  person assylias    schedule 03.04.2014
comment
@assylias Я полностью не согласен. Я не понимаю, что вы имеете в виду, вы застряли. Большинство людей неправильно пишут методы получения и предоставляют прямой доступ к закрытым полям, даже не осознавая этого. Как правило, в большом проекте проще сделать поля общедоступными - это проект, который не предназначен в качестве внешней библиотеки для использования другими.   -  person Jared    schedule 03.04.2014
comment
@jared, тогда давай не будем соглашаться.   -  person assylias    schedule 03.04.2014
comment
@assylias Достаточно честно. Я скажу, однако, что программист должен быть очень осторожен с объявлением полей final. Если у вас есть программа, в которой вы хотите перерабатывать объекты, вы должны быть очень осторожны, чтобы убедиться, что вы действительно можете сбросить объект на что-то новое, если хотите, и final поля ограничивают ваши возможности для этого. И это очень реальная проблема в Java из-за сборки мусора (если вы создаете огромное количество временных объектов, это вызовет проблемы с производительностью) ... вот почему я хотел бы, чтобы в Java была конструкция для размещения объектов на куча.   -  person Jared    schedule 03.04.2014
comment
@ Джаред: Да, вы правы относительно модификатора final, но просто сделать их общедоступными, потому что вы определили их final, - это просто наполовину готово, учитывая, что вы не единственный, кто модифицирует или рефакторинг кода.   -  person thobens    schedule 03.04.2014
comment
@Jared, вы должны быть очень осторожны с полями, отличными от final - многопоточность намного усложняется ...   -  person assylias    schedule 03.04.2014


Ответы (2)


Хотя это не может быть идеальным ответом, ниже однострочный использует только один логический оператор (==) и является кратким.

int daysInMonth = 31 - ((month == 2) ? 3 : ((month - 1) % 7 % 2));

Объяснение этого алгоритма можно найти здесь (Решение №3):

http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month

person a.z.    schedule 03.04.2014
comment
Вау, это действительно интересно. Я никогда не узнал о? условный оператор. Теперь, когда я знаю об этом, я планирую использовать его гораздо больше. Я тоже заметил шаблон, который автор упоминает в статье, но никогда не думал об использовании месяца% 7 для перезапуска шаблона. Спасибо за вклад! - person Holleyj66; 03.04.2014
comment
это сокращение от if else: сначала идет условие, а затем? (= if), то один оператор Java, за которым следует: (= else), за которым следует один оператор Java (см. cafeaulait.org/course/week2/43.html) - person thobens; 03.04.2014
comment
К вашему сведению, синтаксис ?: называется тернарным оператором. (Обратите внимание, что ссылка на страницу Википедии) Хотя это полезно в некоторых сценариях, остерегайтесь написания слишком умного кода, который становится кошмаром для чтения и поддержки. - person Basil Bourque; 03.04.2014

Все дороги устремлены на юг ...

Но я думаю, вы достигли цели своего задания. С моей точки зрения, есть более элегантные способы (и, возможно, быстрее, я думаю, мне нужно провести некоторые измерения), например, использовать Maps или enums, так что вы избегаете уродливых заявлений if - else, подобных этим.

И да, month должно быть окончательным, потому что вы не планируете изменять переменную в этом классе. И да, это нормально, чтобы сделать его приватным (в случае сомнений, он всегда приватный)

person thobens    schedule 03.04.2014
comment
Интересно! Мне было интересно, могли бы вы немного подробнее изучить идею использования «Map», а не условных выражений. Я новичок в этой области, и это меня очень интересует. - person Holleyj66; 03.04.2014
comment
Что ж, я мог бы опубликовать что-то, но должен признать, что это не делает эту конкретную проблему более простой, но более сложной (измеряется строками кода), хотя она была бы более расширяемой. (что не нужно, так как всегда будет 12 месяцев и не больше одного :)) - person thobens; 03.04.2014
comment
см. stackoverflow.com/questions/1298672/, чтобы получить представление о концепции. Это чрезвычайно полезно при работе с динамическим вводом, в то время как от статического ввода (например, месяцев) мало пользы (или даже больше усилий). - person thobens; 03.04.2014