Массивы массивов в Java
Это неприятный для меня... Я парень PHP, работающий на Java в проекте JSP. Я знаю, как делать то, что я пытаюсь использовать слишком много кода и полное отсутствие утонченности.
Я бы предпочел сделать это правильно. Вот ситуация:
Я пишу небольшой дисплей, чтобы показать клиентам, в какие дни они могут поливать свои лужайки на основе их группы полива (ABCDE) и в какое время года это. Наши сезоны выглядят так:
Лето (5-1-8-31)
Spring (от 3-1 до 4-30)
Падение (от 9-1 до 10-31)
Зима (от 11-1 до 2-28)
Пример может быть:
Если я в группе А, здесь будут мои разрешенные времена:
Зима: только по понедельникам
Spring: Вт, Чт, Сб.
Лето: любой день
Падение: Вт, Чт, Сб.
Если бы я писал это на PHP, я бы использовал такие массивы:
//M=Monday,t=Tuesday,T=Thursday.... etc
$schedule["A"]["Winter"]='M';
$schedule["A"]["Spring"]='tTS';
$schedule["A"]["Summer"]='Any';
$schedule["A"]["Fall"]='tTS';
$schedule["B"]["Winter"]='t';
Я МОГУТ делать массивы дней (массив ( "вторник", "четверг", "суббота" ) и т.д., но это не обязательно для того, что я действительно пытаюсь выполнить.
Мне также нужно настроить массивы, чтобы определить, в каком сезоне я нахожусь:
$seasons["Summer"]["start"]=0501;
$seasons["Summer"]["end"]=0801;
Может кто-нибудь предложить действительно классный способ сделать это? Сегодня у меня будет дата и групповое письмо. Мне нужно будет выйти из моей функции в день (М) или в несколько дней (tTS), (Любой).
Ответы
Ответ 1
Вы можете сделать по существу тот же код с Hashtables (или другой Map):
Hashtable<String, Hashtable<String, String>> schedule
= new Hashtable<String, Hashtable<String, String>>();
schedule.put("A", new Hashtable<String, String>());
schedule.put("B", new Hashtable<String, String>());
schedule.put("C", new Hashtable<String, String>());
schedule.put("D", new Hashtable<String, String>());
schedule.put("E", new Hashtable<String, String>());
schedule.get("A").put("Winter", "M");
schedule.get("A").put("Spring", "tTS");
// Etc...
Не так элегантно, но опять же, Java не является динамическим языком и не имеет хэшей на уровне языка.
Примечание. Возможно, вы сможете сделать лучшее решение, это просто появилось у меня в голове, когда я прочитал ваш вопрос.
Ответ 2
Не пытайтесь быть таким же динамичным, как PHP. Вы можете попробовать сначала определить, что вам нужно.
interface Season
{
public string getDays();
}
interface User
{
public Season getWinter();
public Season getSpring();
public Season getSummer();
public Season getFall();
}
interface UserMap
{
public User getUser(string name);
}
И прежде чем использовать его, прочитайте документацию Hashtable. Этот класс синхронизирован, что означает, что каждый вызов защищен от многопоточности, что действительно замедляет доступ, когда вам не нужна дополнительная защита. Используйте Map вместо HashMap или TreeMap.
Ответ 3
Кажется, что каждый пытается найти способ Java, чтобы сделать это, как вы делаете это в PHP, вместо того, как это должно быть сделано на Java. Просто рассмотрите каждую часть вашего массива как объект или, по крайней мере, первый уровень массива как объекта и каждого уровня в качестве переменных внутри объекта. Создайте структуру данных, которую вы заполняете указанными объектами, и получайте доступ к объектам через структуру данных, предоставляемую аксессуарами.
Что-то вроде:
class Schedule
{
private String group;
private String season;
private String rundays;
public Schedule() { this.group = null; this.season = null; this.rundays= null; }
public void setGroup(String g) { this.group = g; }
public String getGroup() { return this.group; }
...
}
public ArrayList<Schedule> schedules = new ArrayList<Schedule>();
Schedule s = new Schedule();
s.setGroup(...);
...
schedules.add(s);
...
Конечно, возможно, это тоже неправильно. Я делаю каждый сезон объектом, и, возможно, каждый будний список также является объектом. Во всяком случае, его более легко использовать, понимать и расширять, чем хэширование Hashtable, которое пытается подражать вашему PHP-коду. Конечно, у PHP тоже есть объекты, и вы должны использовать их подобным образом вместо своих uber-массивов, где это возможно. Однако я понимаю искушение обмануть. PHP делает это так просто и так весело!
Ответ 4
Здесь, как бы он ни выглядел, вы можете понять:
A = new Group();
A.getSeason(Seasons.WINTER).addDay(Days.MONDAY);
A.getSeason(Seasons.SPRING).addDay(Days.TUESDAY).addDay(Days.THURSDAY);
A.getSeason(Seasons.SPRING).addDays(Days.MONDAY, Days.TUESDAY, ...);
schedule = new Schedule();
schedule.addWateringGroup( A );
Ответ 5
Я не программист на Java, но ухожу от Java и просто думаю с точки зрения, что более агностик языка - более чистый способ сделать это может заключаться в использовании либо констант, либо перечисляемых типов. Это должно работать в любом langauge, который поддерживает многомерные массивы.
Если используются именованные константы, где, например:
int A = 0;
int B = 1;
int C = 2;
int D = 3;
int Spring = 0;
int Summer = 1;
int Winter = 2;
int Fall = 3;
...
Затем константы служат в качестве более читаемых индексов массива:
schedule[A][Winter]="M";
schedule[A][Spring]="tTS";
schedule[A][Summer]="Any";
schedule[A][Fall]="tTS";
schedule[B][Winter]="t";
Использование перечисляемых типов:
enum groups
{
A = 0,
B = 1,
C = 2,
D = 3
}
enum seasons
{
Spring = 0,
Summer = 1,
Fall = 2,
Winter = 3
}
...
schedule[groups.A][seasons.Winter]="M";
schedule[groups.A][seasons.Spring]="tTS";
schedule[groups.A][seasons.Summer]="Any";
schedule[groups.A][seasons.Fall]="tTS";
schedule[groups.B][seasons.Winter]="t";
Ответ 6
Я полностью в недоумении, почему некоторые из вас, похоже, думают, что бросать кучу объектов в код - это путь. Например, существует ровно четыре сезона, и они ничего не делают или не хранят. Как это упрощает что-либо, чтобы сделать их объектами? Крыло совершенно верно, что это, вероятно, должно быть константами (или, возможно, перечислениями).
Что Брюс нуждается в этом, это просто таблица поиска. Ему не нужна иерархия объектов и интерфейсов; ему нужен способ поиска расписания на основе сезона и идентификатора группы. Включение вещей в объекты имеет смысл только в том случае, если у них есть обязанности или состояние. Если они не имеют ни одного, то они просто являются идентификаторами, а создание для них специальных объектов просто увеличивает кодовую базу.
Вы могли бы построить, например, Group
объекты, каждый из которых содержит набор строк расписания (по одному для каждого сезона), но если весь объект Group
выполняет функцию поиска, то вы заново изобрели таблицу поиска в гораздо менее интуитивном стиле. Если он должен искать группу, а затем искать расписание, все, что у него есть, это двухэтапная таблица поиска, которая занимает больше времени для кода, скорее всего, будет ошибкой, и ее будет сложнее поддерживать.
Ответ 7
Я использую те, которые предлагают инкапсулирующую функцию в объектах.
import java.util.Date;
import java.util.Map;
import java.util.Set;
public class Group {
private String groupName;
private Map<Season, Set<Day>> schedule;
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public Map<Season, Set<Day>> getSchedule() {
return schedule;
}
public void setSchedule(Map<Season, Set<Day>> schedule) {
this.schedule = schedule;
}
public String getScheduleFor(Date date) {
Season now = Season.getSeason(date);
Set<Day> days = schedule.get(now);
return Day.getDaysForDisplay(days);
}
}
EDIT: Кроме того, ваши диапазоны дат не учитывают високосные годы:
Наши сезоны выглядят так: Лето (5-1-8-31) Spring (от 3-1 до 4-30) Падение (от 9-1 до 10-31) Зима (от 11-1 до 2-28)
Ответ 8
Я согласен, что вы должны определенно поставить эту логику на чистый интерфейс:
public String lookupDays(String group, String date);
но, возможно, вы должны вставить данные в файл свойств. Я не против жесткого кодирования этих данных в ваших исходных файлах, но, как вы заметили, Java может быть довольно многословным, когда дело доходит до вложенных коллекций. Ваш файл может выглядеть так:
A.Summer = M
A.Spring = TTS
B.Summer = Т
Обычно мне не нравится перемещать статические данные, подобные этому, во внешний файл, потому что он увеличивает "расстояние" между данными и кодом, который его использует. Однако, когда вы имеете дело с вложенными коллекциями, особенно с картами, все может стать настоящим уродливым, реальным быстрым.
Если вам не нравится эта идея, возможно, вы можете сделать что-то вроде этого:
public class WaterScheduler
{
private static final Map<String, String> GROUP2SEASON = new HashMap<String, String>();
static
{
addEntry("A", "Summer", "M");
addEntry("A", "Spring", "tTS");
addEntry("B", "Summer", "T");
}
private static void addEntry(String group, String season, String value)
{
GROUP2SEASON.put(group + "." + season, value);
}
}
Вы теряете некоторую читаемость, но по крайней мере данные ближе к тому, где они будут использоваться.
Ответ 9
Лучшим решением, возможно, было бы поместить все эти данные в базу данных, вместо жесткого кодирования в ваших источниках или с помощью файлов свойств.
Использование базы данных будет намного проще в обслуживании, и существует сорт бесплатно база данных двигатели на выбор.
Два из этих механизмов базы данных полностью реализованы на Java и могут быть встроены в приложение, просто включив файл jar. Это немного тяжеловесный, конечно, но он намного более масштабируемый и более простой в обслуживании. Просто потому, что сегодня есть 20 записей, это не означает, что не будет более поздних из-за изменения требований или ползучести функции.
Если через несколько недель или месяцев вы решите, что хотите добавить, скажем, временные ограничения на воду, будет намного проще добавить эту функциональность, если вы уже используете базу данных. Даже если этого не произойдет, вы потратили несколько часов на изучение того, как внедрить базу данных в приложение.
Ответ 10
Должен ли параметр "дата" быть параметром? Если вы просто показываете текущий график полива, сам класс WateringSchedule может выяснить, в какой день это происходит, и поэтому в каком сезоне он есть. Затем просто введите метод, который возвращает карту, где ключ является буквой группы. Что-то вроде:
public Map<String,List<String>> getGroupToScheduledDaysMap() {
// instantiate a date or whatever to decide what Map to return
}
Затем на странице JSP
<c:forEach var="day" items="${scheduler.groupToScheduledDaysMap["A"]}">
${day}
</c:forEach>
Если вам нужно показывать расписания более одного сезона, у вас должен быть метод в классе WateringSchedule, который возвращает карту, где Seasons являются ключами, а затем Maps of groupToScheduledDays являются значениями.
Ответ 11
Нет никакого правильного решения. Java просто не делает такие вещи хорошо. Решение Mike - это в значительной степени способ сделать это, если вы хотите, чтобы строки были индексом (ключами). Другой вариант, если настройка хеш-хэшей слишком уродлива, состоит в том, чтобы присоединить строки вместе (бесстыдно украденные с Майка и измененные):
Hashtable<String, String> schedule = new Hashtable<String, String>();
schedule.put("A-Winter", "M");
schedule.put("A-Spring", "tTS");
а затем поиск:
String val = schedule.get(group + "-" + season);
Если вы недовольны общим уродством (и я не обвиняю вас), положите все это на вызов метода:
String whenCanIWater(String group, Date date) { /* ugliness here */ }
Ответ 12
TL;DR
Используя современные функции и классы языка Java, определите свои собственные перечисления для представления сезонов и групп.
Schedule.daysForGroupOnDate(
Group.D ,
LocalDate.now()
)
Этот метод дает Set
объектов DayOfWeek
enum (а не только текст!), например DayOfWeek.TUESDAY
и DayOfWeek.THURSDAY
.
Современная Java
Может кто-нибудь предложить действительно классный способ сделать это?
Да.
Современная Java имеет встроенные классы, коллекции и перечисления, которые помогут вам справиться с этой проблемой.
Структура java.time, встроенная в Java, предлагает Month
enum и DayOfWeek
перечисление.
EnumSet
и EnumMap
обеспечить реализацию Set
и Map
, которые оптимизированы для использования с перечислениями для быстрого выполнения в очень маленькой памяти.
Вы можете определить свой собственный enums для представления своего сезона и ваших групп (A, B и т.д.). Объект enum в Java намного полезнее и мощнее, чем на других языках. Если вы не знакомы, см. Учебник Oracle.
Простой синтаксис определения собственных перечислений фактически обеспечивает большую часть функций, необходимых для решения этого Вопроса, устраняя сложное кодирование. Новый литерал синтаксис для наборов и карт в коллекциях factory методов в Java 9 (JEP 269) делает код еще проще.
Вот полное рабочее приложение. Обратите внимание, как мало кода существует для алгоритмов. Определение собственных пользовательских перечислений делает большую часть тяжелой работы.
Одно предостережение с этим кодом приложения: он не принимает никаких изменений в ваших бизнес-определениях, или, по крайней мере, если есть изменения, вам нужны только текущие правила, "самое последнее самое лучшее". Если ваши правила меняются со временем, и вам нужно представить все прошлые, настоящие и будущие версии, я бы построил совсем другое приложение, возможно, с базой данных для хранения правил. Но это приложение здесь решает вопрос, как было задано.
Season
Представьте свой сезон как enum Season
. Каждый объект сезона содержит List
Month
перечисляющие объекты, которые определяют длину этого конкретного сезона. Новый синтаксис List.of
, добавленный в Java 9, определяет неизменяемый список в синтаксисе литералов с помощью статических методов factory.
package com.basilbourque.watering;
import java.time.LocalDate;
import java.time.Month;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
public enum Season
{
SPRING( List.of( Month.MARCH , Month.APRIL ) ),
SUMMER( List.of( Month.MAY , Month.JUNE, Month.JULY , Month.AUGUST ) ),
FALL( List.of( Month.SEPTEMBER , Month.OCTOBER ) ),
WINTER( List.of( Month.NOVEMBER , Month.DECEMBER , Month.JANUARY , Month.FEBRUARY ) );
private List< Month > months;
// Constructor
Season ( List < Month > monthsArg )
{
this.months = monthsArg;
}
public List < Month > getMonths ( )
{
return this.months;
}
// For any given month, determine the season.
static public Season ofLocalMonth ( Month monthArg )
{
Season s = null;
for ( Season season : EnumSet.allOf( Season.class ) )
{
if ( season.getMonths().contains( monthArg ) )
{
s = season;
break; // Bail out of this FOR loop.
}
}
return s;
}
// For any given date, determine the season.
static public Season ofLocalDate ( LocalDate localDateArg )
{
Month month = localDateArg.getMonth();
Season s = Season.ofLocalMonth( month );
return s;
}
// Run `main` for demo/testing.
public static void main ( String[] args )
{
// Dump all these enum objects to console.
for ( Season season : EnumSet.allOf( Season.class ) )
{
System.out.println( "Season: " + season.toString() + " = " + season.getMonths() );
}
}
}
Group
Представляйте каждую группу клиентов газонов/ярдов (A, B, C, D, E) как перечисление с именем Group
. Каждый из этих объектов перечисления содержит Map
, отображающий объект Season
enum для Set
объектов DayOfWeek
enum. Например, Group.A
в Season.SPRING
позволяет полировать через два дня, DayOfWeek.TUESDAY
и DayOfWeek.THURSDAY
.
package com.basilbourque.watering;
import java.time.DayOfWeek;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
public enum Group
{
A(
Map.of(
Season.SPRING , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
Season.WINTER , EnumSet.of( DayOfWeek.TUESDAY )
)
),
B(
Map.of(
Season.SPRING , EnumSet.of( DayOfWeek.FRIDAY ) ,
Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.FRIDAY ) ,
Season.WINTER , EnumSet.of( DayOfWeek.FRIDAY )
)
),
C(
Map.of(
Season.SPRING , EnumSet.of( DayOfWeek.MONDAY ) ,
Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
Season.FALL , EnumSet.of( DayOfWeek.MONDAY , DayOfWeek.TUESDAY ) ,
Season.WINTER , EnumSet.of( DayOfWeek.MONDAY )
)
),
D(
Map.of(
Season.SPRING , EnumSet.of( DayOfWeek.WEDNESDAY , DayOfWeek.FRIDAY ) ,
Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
Season.FALL , EnumSet.of( DayOfWeek.FRIDAY ) ,
Season.WINTER , EnumSet.of( DayOfWeek.WEDNESDAY )
)
),
E(
Map.of(
Season.SPRING , EnumSet.of( DayOfWeek.TUESDAY ) ,
Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY ) ,
Season.WINTER , EnumSet.of( DayOfWeek.WEDNESDAY )
)
);
private Map < Season, Set < DayOfWeek > > map;
// Constructor
Group ( Map < Season, Set < DayOfWeek > > mapArg )
{
this.map = mapArg;
}
// Getter
private Map < Season, Set < DayOfWeek > > getMapOfSeasonToDaysOfWeek() {
return this.map ;
}
// Retrieve the DayOfWeek set for this particular Group.
public Set<DayOfWeek> daysForSeason (Season season ) {
Set<DayOfWeek> days = this.map.get( season ) ; // Retrieve the value (set of days) for this key (a season) for this particular grouping of lawns/yards.
return days;
}
// Run `main` for demo/testing.
public static void main ( String[] args )
{
// Dump all these enum objects to console.
for ( Group group : EnumSet.allOf( Group.class ) )
{
System.out.println( "Group: " + group.toString() + " = " + group.getMapOfSeasonToDaysOfWeek() );
}
}
}
Schedule
Потяните все это вместе в этом классе Schedule
.
Этот класс использует перечисленные выше перечисления, чтобы получить полезную работу. Единственный внедренный до сих пор метод подсказывает, какие дни недели разрешены для определенной группы в определенную дату. Метод определяет, к какому Season
относится к этой дате.
Запустите метод main
здесь, чтобы сбрасывать содержимое двух наших перечислений и сообщать о днях недели, позволяя поливать в каждой группе конкретную жестко запрограммированную дату.
package com.basilbourque.watering;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import java.util.EnumSet;
import java.util.Set;
public class Schedule
{
static private DateTimeFormatter isoWeekFormatter = DateTimeFormatter.ofPattern( "uuuu-'W'ww" ) ;
static public Set < DayOfWeek > daysForGroupOnDate ( Group group , LocalDate localDate )
{
Season season = Season.ofLocalDate( localDate );
Set < DayOfWeek > days = group.daysForSeason( season );
return days;
}
// Run `main` for demo/testing.
public static void main ( String[] args )
{
Season.main( null );
Group.main( null );
// Dump all these enum objects to console.
for ( Group group : EnumSet.allOf( Group.class ) )
{
LocalDate localDate = LocalDate.now( ZoneId.of( "Africa/Tunis" ) );
Set < DayOfWeek > days = Schedule.daysForGroupOnDate( group , localDate );
String week = localDate.format( Schedule.isoWeekFormatter ) ; // Standard ISO 8601 week, where week number one has the first Thursday of the calendar year, and week starts on Monday, so year is either 52 or 53 weeks long.
String message = "Group " + group + " – Watering days on " + localDate + " week # " + week + " is: " + days;
System.out.println( message );
}
}
}
Консоль
При запуске Schedule.main
мы видим, что это сбрасывается на консоль.
Сезон: SPRING= [MARCH, APRIL]
Сезон: ЛЕТО = [МОЖЕТ, ИЮНЬ, ИЮЛЬ, АВГУСТ]
Сезон: FALL = [СЕНТЯБРЬ, ОКТЯБРЬ]
Сезон: ЗИМА = [НОЯБРЬ, ДЕКАБРЬ, ЯНВАРЬ, ФЕВРАЛЬ]
Группа: A = { SPRING= [ВТОРНИК, ЧЕТВЕРГ], FALL = [ВТОРНИК, ЧЕТВЕРГ], ЛЕТО = [ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, ЧЕТВЕРГ, ПЯТНИЦА, СУББОТА, ВОСКРЕСЕНЬЕ), ЗИМА = [ВТОРНИК]}
Группа: B = { SPRING= [FRIDAY], FALL = [ВТОРНИК, ПЯТНИЦА], ЛЕТО = [ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, ЧЕТВЕРГ, ПЯТНИЦА, СУББОТА, ВОСКРЕСЕНЬЕ), ЗИМА = [ПЯТНИЦА]}
Группа: C = { SPRING= [ПОНЕДЕЛЬНИК], ПАДЕНИЕ = [ПОНЕДЕЛЬНИК, ВТОРНИК], ЛЕТО = [ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, ЧЕТВЕРГ, ПЯТНИЦА, СУББОТА, ВОСКРЕСЕНЬЕ), ЗИМА = [ПОНЕДЕЛЬНИК]}
Группа: D = { SPRING= [СРЕДА, ПЯТНИЦА], FALL = [ПЯТНИЦА], ЛЕТО = [ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, ЧЕТВЕРГ, ПЯТНИЦА, СУББОТА, ВОСКРЕСЕНЬЕ), ЗИМА = [СРЕДА]}
Группа: E = { SPRING= [ВТОРНИК], FALL = [ВТОРНИК, СРЕДА], ЛЕТО = [ПОНЕДЕЛЬНИК, ВТОРНИК, СРЕДА, ЧЕТВЕРГ, ПЯТНИЦА, СУББОТА, ВОСКРЕСЕНЬЕ), ЗИМА = [СРЕДА]}
Группа A - Дни полива на 2018-01-30 неделе # 2018-W05: [ВТОРНИК]
Группа B - дни полива на 2018-01-30 неделе # 2018-W05: [ПЯТНИЦА]
Группа C - дни полива на 2018-01-30 неделе # 2018-W05: [ПОНЕДЕЛЬНИК]
Группа D - дни полива на 2018-01-30 неделе # 2018-W05: [СРЕДА]
Группа E - дни полива на 2018-01-30 неделе # 2018-W05: [СРЕДА]
ISO 8601 неделя
Вам может быть полезно узнать о стандарте ISO 8601 для определение недели. Стандарт дает конкретное значение для "недели" и определяет текстовый формат для представления определенной недели или определенного дня на этой неделе.
Для работы с такими неделями в Java рассмотрите возможность добавления библиотеки ThreeTen-Extra в ваш проект, чтобы использовать YearWeek
class.
LocalDate
Класс LocalDate
представляет значение только для даты без времени и без часового пояса.
Часовой пояс имеет решающее значение для определения даты. В любой данный момент дата изменяется по всему миру по зонам. Например, через несколько минут после полуночи в Paris France - это новый день, пока еще "вчера" в Монреаль Квебек.
Если часовой пояс не указан, JVM неявно применяет текущий часовой пояс по умолчанию. Это значение по умолчанию может измениться в любой момент, поэтому ваши результаты могут отличаться. Лучше указывать желаемый/ожидаемый часовой пояс явно как аргумент.
Укажите имя часового пояса в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте аббревиатуру 3-4 буквы, например EST
или IST
, поскольку они не являются настоящими часовыми поясами, а не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Если вы хотите использовать текущий часовой пояс JVMs, запросите его и передайте в качестве аргумента. Если этот параметр опущен, то действующий по умолчанию JVM применяется неявно. Лучше быть явным.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Или укажите дату. Вы можете установить месяц на номер, с нормальным номером 1-12 за январь-декабрь.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Или, лучше, используйте Month
предопределенные объекты перечисления, по одному для каждого месяца года. Совет. Используйте эти объекты Month
на всей вашей кодовой базе, а не просто целое число, чтобы сделать ваш код более самодокументированным, обеспечить допустимые значения и предоставить type- безопасность.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Неизменяемые коллекции
Списки, наборы и карты, рассмотренные выше, в идеале должны быть неизменными коллекциями, поскольку изменение членства в этих коллекциях, вероятно, будет путаным и ошибочным.
Новый синтаксис Java 9 List.of
и Map.of
уже обещал быть неизменным. Однако в нашем случае Map
в идеале должен быть EnumMap
для эффективности работы и памяти. Текущая реализация Map.of
и Set.of
, по-видимому, не обнаруживает использования перечислений в качестве элементов и автоматически оптимизируется при внутреннем использовании EnumMap
и EnumSet
. Существует проблема OpenJDK, открытая для рассмотрения таких проблем: рассмотреть усовершенствования EnumMap и EnumSet.
Один из способов получения неизменяемого EnumSet и неизменяемого EnumMap через Google Guava:
В результатах каждого из них используется базовый EnumSet
/EnumMap
. Операции, такие как get
и put
, вызывают исключение. Таким образом, вы получаете оптимизацию, связанную с enum, и неизменность.
Ниже приведены классы Season
и Group
, описанные выше, чтобы использовать библиотеку Google Guava 23.6.
Season
с неизменяемостью
package com.basilbourque.watering;
import java.time.LocalDate;
import java.time.Month;
import java.util.EnumSet;
import java.util.List;
public enum Season
{
SPRING( List.of( Month.MARCH , Month.APRIL ) ), // `List.of` provides literals-style syntax, and returns an immutable `List`. New in Java 9.
SUMMER( List.of( Month.MAY , Month.JUNE, Month.JULY , Month.AUGUST ) ),
FALL( List.of( Month.SEPTEMBER , Month.OCTOBER ) ),
WINTER( List.of( Month.NOVEMBER , Month.DECEMBER , Month.JANUARY , Month.FEBRUARY ) );
private List< Month > months;
// Constructor
Season ( List < Month > monthsArg )
{
this.months = monthsArg;
}
public List < Month > getMonths ( )
{
return this.months;
}
// For any given month, determine the season.
static public Season ofLocalMonth ( Month monthArg )
{
Season s = null;
for ( Season season : EnumSet.allOf( Season.class ) )
{
if ( season.getMonths().contains( monthArg ) )
{
s = season;
break; // Bail out of this FOR loop.
}
}
return s;
}
// For any given date, determine the season.
static public Season ofLocalDate ( LocalDate localDateArg )
{
Month month = localDateArg.getMonth();
Season s = Season.ofLocalMonth( month );
return s;
}
// Run `main` for demo/testing.
public static void main ( String[] args )
{
// Dump all these enum objects to console.
for ( Season season : EnumSet.allOf( Season.class ) )
{
System.out.println( "Season: " + season.toString() + " = " + season.getMonths() );
}
}
}
Group
с неизменяемостью
package com.basilbourque.watering;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.time.DayOfWeek;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
public enum Group
{
A(
Maps.immutableEnumMap(
Map.of( // `Map.of` provides literals-style syntax, and returns an immutable `Map`. New in Java 9.
Season.SPRING , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
Season.FALL , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
Season.WINTER , Sets.immutableEnumSet( DayOfWeek.TUESDAY )
)
)
),
B(
Maps.immutableEnumMap(
Map.of(
Season.SPRING , Sets.immutableEnumSet( DayOfWeek.FRIDAY ) ,
Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
Season.FALL , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.FRIDAY ) ,
Season.WINTER , Sets.immutableEnumSet( DayOfWeek.FRIDAY )
)
)
),
C(
Maps.immutableEnumMap(
Map.of(
Season.SPRING , Sets.immutableEnumSet( DayOfWeek.MONDAY ) ,
Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
Season.FALL , Sets.immutableEnumSet( DayOfWeek.MONDAY , DayOfWeek.TUESDAY ) ,
Season.WINTER , Sets.immutableEnumSet( DayOfWeek.MONDAY )
)
)
),
D(
Maps.immutableEnumMap(
Map.of(
Season.SPRING , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY , DayOfWeek.FRIDAY ) ,
Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
Season.FALL , Sets.immutableEnumSet( DayOfWeek.FRIDAY ) ,
Season.WINTER , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY )
)
)
),
E(
Maps.immutableEnumMap(
Map.of(
Season.SPRING , Sets.immutableEnumSet( DayOfWeek.TUESDAY ) ,
Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
Season.FALL , Sets.immutableEnumSet( EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY ) ) ,
Season.WINTER , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY )
)
)
);
private Map < Season, Set < DayOfWeek > > map;
// Constructor
Group ( Map < Season, Set < DayOfWeek > > mapArg )
{
this.map = mapArg;
}
// Getter
private Map < Season, Set < DayOfWeek > > getMapOfSeasonToDaysOfWeek ( )
{
return this.map;
}
// Retrieve the DayOfWeek set for this particular Group.
public Set < DayOfWeek > daysForSeason ( Season season )
{
Set < DayOfWeek > days = this.map.get( season ); // Retrieve the value (set of days) for this key (a season) for this particular grouping of lawns/yards.
return days;
}
// Run `main` for demo/testing.
public static void main ( String[] args )
{
// Dump all these enum objects to console.
for ( Group group : EnumSet.allOf( Group.class ) )
{
System.out.println( "Group: " + group.toString() + " = " + group.getMapOfSeasonToDaysOfWeek() );
}
}
}
О java.time
java.timeframework встроен в Java 8 и более поздние версии. Эти классы вытесняют неприятный старый legacy классы даты-времени, такие как java.util.Date
, Calendar
и SimpleDateFormat
.
Проект Joda-Time, теперь режим обслуживания, советуем перейти к классам java.time.
Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация JSR 310.
Где получить классы java.time?
Проект ThreeTen-Extra расширяет java.time с помощью дополнительных классов. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и больше.