Arrays of Arrays in Java
对我来说这是一个讨厌的人。我知道如何通过过多的代码和完全缺乏技巧来做我要尝试的事情。
我宁愿做对。情况如下:
我正在写一个小显示器,以根据客户的浇水组(ABCDE)向客户展示他们可以在几天浇水,以及一年中的什么时间。我们的季节如下所示:
夏季(5-1至8-31)
春季(3-1至4-30)
下降(9-1至10-31)
冬季(11-1至2-28)
一个示例可能是:
如果我在A组中,这将是我允许的时间:
冬季:仅星期一
春季:周二,周四,周六
夏季:任何一天
秋季:周二,周四,周六
如果我是用PHP编写的,则将使用如下数组:
1 2 3 4 5 6
| //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'; |
我可以制作days数组(array(" Tuesday"," Thursday"," Saturday"))等,但是对于我真正想要完成的事情,这不是必需的。
我还需要设置数组以确定我所在的季节:
1 2
| $seasons["Summer"]["start"]=0501;
$seasons["Summer"]["end"]=0801; |
有人可以建议一种非常酷的方法吗?我要有今天的日期和团体信。我将需要一天(M)或一系列天(tTS),(任何)退出我的功能。
不要尝试像PHP一样动态。您可以尝试首先定义所需的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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。
您可以使用Hashtables(或其他一些Map)执行基本上相同的代码:
1 2 3 4 5 6 7 8 9 10 11
| 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并不是一种动态语言,并且在语言级别上没有哈希。
注意:您也许可以做一个更好的解决方案,当我阅读您的问题时,这突然出现在我的脑海中。
似乎每个人都在尝试找到Java的实现方式,就像您在PHP中那样,而不是在Java中应采用的方式。只需将数组的每个部分都视为一个对象,或者至少将数组的第一级视为一个对象,并将每个子级视为该对象内部的变量。构建一个数据结构,您可以用所述对象填充该数据结构,并通过数据结构的给定访问器访问这些对象。
就像是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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);
... |
当然那也不对。我将每个季节作为对象,也许每个工作日也将其作为对象。无论如何,它比试图模仿您的PHP代码的笨拙的Hashtable更容易重用,理解和扩展。当然,PHP也有对象,并且您应该尽可能以类似的方式使用它们,而不是使用超级数组。我确实理解作弊的诱惑。 PHP使它变得如此简单和有趣!
这是一种可能的样子,您可以弄清楚其余部分:
1 2 3 4 5 6 7
| 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 ); |
我不是Java程序员,而是摆脱了Java的束缚,而只是用与语言无关的术语来思考-一种更简洁的方法可能是使用常量或枚举类型。这应该在支持多维数组的任何语言中都有效。
如果使用命名常量,例如:
1 2 3 4 5 6 7 8 9 10
| int A = 0;
int B = 1;
int C = 2;
int D = 3;
int Spring = 0;
int Summer = 1;
int Winter = 2;
int Fall = 3;
... |
然后,常量用作更易读的数组下标:
1 2 3 4 5
| schedule[A][Winter]="M";
schedule[A][Spring]="tTS";
schedule[A][Summer]="Any";
schedule[A][Fall]="tTS";
schedule[B][Winter]="t"; |
使用枚举类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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"; |
我和那些建议在对象中封装功能的人在一起。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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);
}
} |
编辑:此外,您的日期范围不考虑leap年:
Our seasons look like this: Summer
(5-1 to 8-31) Spring (3-1 to 4-30)
Fall (9-1 to 10-31) Winter (11-1 to
2-28)
我完全茫然不知为什么有些人似乎认为将对象的对象扔到代码上是必经之路。例如,恰好有四个季节,它们不做任何事情或存储任何东西。如何简化使它们成为对象的任何事物? Wing说的很对,这些应该应该是常量(或者可能是枚举)。
本质上,Bruce需要的只是一个查询表。他不需要对象和接口的层次结构。他需要一种方法来根据季节和组标识符查找时间表。仅当它们具有责任或状态时,才将它们变成对象。如果它们都没有,那么它们只是标识符,为它们构建特殊的对象只会使代码库变大。
例如,您可以构建Group对象,每个对象都包含一组计划字符串(每个季节一个),但是如果所有Group对象所做的都是提供查找功能,那么您已经在很多方面重新构造了查找表不太直观的时尚。如果他必须先查找组,然后再查找时间表,那么他所拥有的只是一个两步查找表,该表花了较长的时间编写代码,更有可能是儿童车,而且较难维护。
是否必须将"日期"作为参数?如果仅显示当前的浇水时间表,WateringSchedule类本身可以确定是哪一天,以及什么季节。然后只有一种方法可以返回映射,其中Key是组字母。就像是:
1 2 3
| public Map<String,List<String>> getGroupToScheduledDaysMap() {
// instantiate a date or whatever to decide what Map to return
} |
然后在JSP页面
1 2 3
| <c:forEach var="day" items="${scheduler.groupToScheduledDaysMap["A"]}">
${day}
</c:forEach> |
如果需要显示一个以上季节的时间表,则WateringSchedule类中应该有一个方法,该方法返回一个以Seasons为键,然后以groupToScheduledDays为值的Maps的地图。
更好的解决方案可能是将所有数据放入数据库中,而不是在源中或使用属性文件对其进行硬编码。
使用数据库将更容易维护,并且有多种免费的数据库引擎可供选择。
这些数据库引擎中的两个完全用Java实现,只需包含jar文件就可以将它们嵌入到应用程序中。当然,它有点重量级,但是它具有更大的可伸缩性和易于维护。仅仅因为今天有20条记录,并不意味着以后由于需求的变化或功能变化而不会再有更多记录。
如果您在几周或几个月内决定要添加一天中的浇水限制,那么如果您已经在使用数据库,则添加该功能会容易得多。即使从未发生过,您也已经花了几个小时学习如何在应用程序中嵌入数据库。
我同意您绝对应该将此逻辑放在干净的接口后面:
1
| public String lookupDays(String group, String date); |
但是也许您应该将数据粘贴到属性文件中。我不反对在源文件中对这些数据进行硬编码,但是,正如您所注意到的,在嵌套Collections方面,Java可能非常罗word。您的文件可能看起来像:
A.Summer=M
A.Spring=tTS
B.Summer=T
通常,我不喜欢将这样的静态数据移动到外部文件,因为它会增加数据与使用它的代码之间的"距离"。但是,每当您处理嵌套的Collection(尤其是地图)时,事情都会变得非常丑陋,快速。
如果您不喜欢这个主意,也许您可??以做这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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);
}
} |
您失去了一些可读性,但至少数据更接近将要使用的位置。
tl; dr
使用现代Java语言功能和类,定义自己的枚举以表示季节和组。
好。
1 2 3 4
| Schedule.daysForGroupOnDate(
Group.D ,
LocalDate.now()
) |
该方法产生Set个DayOfWeek枚举对象(不仅仅是文本!),例如DayOfWeek.TUESDAY和DayOfWeek.THURSDAY。
好。
现代爪哇
Can anyone suggest a really cool way to do this?
Ok.
是。
好。
现代Java具有内置的类,集合和枚举来帮助您解决此问题。
好。
Java内置的java.time框架提供Month枚举和DayOfWeek枚举。
好。
EnumSet和EnumMap提供Set和Map的实现,这些实现经过优化,可与枚举一起使用,从而在很少的内存中快速执行。
好。
您可以定义自己的枚举来表示季节和组(A,B等)。与其他语言相比,Java中的枚举功能更加有用和强大。如果不熟悉,请参见《 Oracle教程》。
好。
定义自己的枚举的简单语法实际上提供了解决此问题所需的许多功能,从而消除了一些复杂的编码。 Java 9(JEP 269)中的collections工厂方法中的集合和映射的新文字语法使代码现在变得更加简单。
好。
这是一个完整的工作应用程序。请注意,用于算法的代码很少。定义您自己的自定义枚举可完成大部分繁重的工作。
好。
使用此应用程序代码的一个警告:它假定您的业务定义中没有任何更改,或者至少在您仅关心当前规则的更改中,"最新最大"。如果您的规则随时间变化,并且您需要代表过去,现在和将来的所有版本,那么我将构建一个非常不同的应用程序,可能带有一个存储规则的数据库。但是这个程序在这里解决了问的问题。
好。
Season
将您的季节表示为枚举Season。每个季节对象都包含一个List of Month枚举对象,这些枚举对象定义了特定季节的长度。 Java 9中添加的新List.of语法通过静态工厂方法以文字语法定义了一个不可变列表。
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| 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枚举对象映射到DayOfWeek枚举对象的Set。例如,Season.SPRING中的Group.A允许在两天(DayOfWeek.TUESDAY和DayOfWeek.THURSDAY)浇水。
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| 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方法以转储我们两个枚举的内容,并报告一周中的每一天,以便在特定的硬编码日期下每组浇水。
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| 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时,我们看到此内容已转储到控制台。
好。
Season: SPRING = [MARCH, APRIL]
Ok.
Season: SUMMER = [MAY, JUNE, JULY, AUGUST]
Ok.
Season: FALL = [SEPTEMBER, OCTOBER]
Ok.
Season: WINTER = [NOVEMBER, DECEMBER, JANUARY, FEBRUARY]
Ok.
Group: A = {SPRING=[TUESDAY, THURSDAY], FALL=[TUESDAY, THURSDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[TUESDAY]}
Ok.
Group: B = {SPRING=[FRIDAY], FALL=[TUESDAY, FRIDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[FRIDAY]}
Ok.
Group: C = {SPRING=[MONDAY], FALL=[MONDAY, TUESDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[MONDAY]}
Ok.
Group: D = {SPRING=[WEDNESDAY, FRIDAY], FALL=[FRIDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[WEDNESDAY]}
Ok.
Group: E = {SPRING=[TUESDAY], FALL=[TUESDAY, WEDNESDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[WEDNESDAY]}
Ok.
Group A – Watering days on 2018-01-30 week # 2018-W05 is: [TUESDAY]
Ok.
Group B – Watering days on 2018-01-30 week # 2018-W05 is: [FRIDAY]
Ok.
Group C – Watering days on 2018-01-30 week # 2018-W05 is: [MONDAY]
Ok.
Group D – Watering days on 2018-01-30 week # 2018-W05 is: [WEDNESDAY]
Ok.
Group E – Watering days on 2018-01-30 week # 2018-W05 is: [WEDNESDAY]
Ok.
ISO 8601周
您可能会发现了解ISO 8601标准一周的定义会有所帮助。该标准为"星期"赋予了特定含义,并定义了一种文本格式,用于表示一周中的特定星期或特定日期。
好。
为了在Java中使用这些星期,请考虑将ThreeTen-Extra库添加到项目中以使用YearWeek类。
好。
LocalDate
LocalDate类表示没有日期和时区的仅日期值。
好。
时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是"昨天"。
好。
如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您的期望/期望时区明确指定为参数。
好。
以continent/region格式指定正确的时区名称,例如America/Montreal,Africa/Casablanca或Pacific/Auckland。切勿使用3-4个字母的缩写,例如EST或IST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
好。
1 2
| ZoneId z = ZoneId.of("America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ; |
如果要使用JVM的当前默认时区,请提出要求并作为参数传递。如果省略,则会隐式应用JVM的当前默认值。最好明确一点。
好。
1
| ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone. |
或指定一个日期。您可以用数字设置月份,一月至十二月的理智编号为1-12。
好。
1
| 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对象,而不仅仅是一个整数,可以使您的代码更具自记录性,确保有效值并提供类型安全性。
好。
1
| 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库:
好。
Sets.immutableEnumSet( … )
Maps.immutableEnumMap( … )
好。
每个结果都使用基础EnumSet / EnumMap。 get和put之类的操作会引发异常。因此,您可以获得与枚举相关的优化以及不变性。
好。
这是上面看到的Season和Group类,已修改为使用Google Guava 23.6库。
好。
Season具有不变性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| 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具有不变性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| 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.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧旧式日期时间类,例如java.util.Date,Calendar和SimpleDateFormat。
好。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
好。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
好。
在哪里获取java.time类?
好。
Java SE 8,Java SE 9和更高版本
内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。
好。
Java SE 6和Java SE 7
java.time的许多功能在ThreeTen-Backport中都被反向移植到Java 6和7。
好。
安卓系统
更高版本的Android捆绑了java.time类的实现。
对于较早的Android,ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。 请参阅如何使用ThreeTenABP…。
好。
好。
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目为将来可能在java.time中添加内容提供了一个试验场。 您可能会在这里找到一些有用的类,例如Interval,YearWeek,YearQuarter等。
好。
好。
没有很好的解决方案。 Java只是做得不好。如果您想将字符串用作索引(键),则Mike的解决方案几乎就是该方法。如果哈希设置太丑陋,另一个选择是将字符串附加在一起(从Mike偷偷偷偷修改):
1 2 3
| Hashtable<String, String> schedule = new Hashtable<String, String>();
schedule.put("A-Winter","M");
schedule.put("A-Spring","tTS"); |
然后查找:
1
| String val = schedule.get(group +"-" + season); |
如果您对一般的丑陋不满意(我也不会怪您),请将其全部放在方法调用后面:
1
| String whenCanIWater(String group, Date date) { /* ugliness here */ } |
|