【问题标题】:Arrays of Arrays in JavaJava中的数组数组
【发布时间】:2010-09-05 23:40:45
【问题描述】:

这对我来说很糟糕...我是一名 PHP 人,在 Java 中从事 JSP 项目。我知道如何通过太多代码和完全缺乏技巧来做我正在尝试的事情。

我宁愿做正确的事。情况如下:

我正在编写一个小型显示器,以根据客户的浇水组 (ABCDE) 和一年中的什么时间向客户展示他们可以在哪些日子浇灌草坪。我们的季节是这样的: 夏季(5-1 至 8-31) 弹簧(3-1 至 4-30) 秋季(9-1 至 10-31) 冬季(11-1 至 2-28)

一个例子可能是:

如果我在 A 组,以下是我允许的时间: 冬季:仅限周一 春季:周二、周四、周六 夏季:任何一天 秋季:周二、周四、周六

如果我是用 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';

我可以制作天数数组 (array("Tuesday","Thursday","Saturday")) 等,但对于我真正想要完成的事情来说,这不是必需的。

我还需要设置数组来确定我所处的季节:

$seasons["Summer"]["start"]=0501;
$seasons["Summer"]["end"]=0801;

谁能提出一个非常酷的方法来做到这一点?我会有今天的约会和群信。我将需要一天 (M) 或一系列天 (tTS)、(Any) 退出我的职能。

【问题讨论】:

    标签: java php jsp tomcat


    【解决方案1】:

    tl;博士

    使用现代 Java 语言功能和类,定义您自己的枚举来表示季节和组。

    Schedule.daysForGroupOnDate( 
        Group.D , 
        LocalDate.now()
    )  
    

    该方法生成SetDayOfWeek 枚举对象(不仅仅是文本!),例如DayOfWeek.TUESDAYDayOfWeek.THURSDAY

    现代 Java

    谁能提出一个非常酷的方法来做到这一点?

    是的。

    现代 Java 有内置的类、集合和枚举来帮助您解决这个问题。

    Java 中内置的 java.time 框架提供了Month 枚举和DayOfWeek 枚举。

    EnumSetEnumMap 提供了 SetMap 的实现,这些实现经过优化,可与枚举一起使用,以便在很少的内存中快速执行。

    您可以定义自己的enums 来代表您的季节和您的组(A、B 等)。 Java 中的枚举工具比其他语言中的枚举工具更有用、更强大。如果不熟悉,请参阅Oracle Tutorial

    定义自己的枚举的简单语法实际上提供了解决这个问题所需的大部分功能,消除了一些复杂的编码。 Java 9 (JEP 269) 中 collections factory methods 中用于集合和映射的新 literals syntax 使代码现在更加简单。

    这是一个完整的工作应用程序。 请注意算法代码很少。定义您自己的自定义枚举可以完成大部分繁重的工作。

    此应用程序代码的一个警告:它假设您的业务定义没有任何变化,或者至少如果有变化,您只关心当前规则,“最新的就是最好的”。如果您的规则随时间而变化,并且您需要表示所有过去、现在和未来的版本,我会构建一个非常不同的应用程序,可能会使用一个数据库来存储规则。但是这个应用程序在这里解决了所问的问题。

    Season

    将您的季节表示为枚举 Season。每个季节对象都包含一个 ListMonth 枚举对象,这些对象定义了该特定季节的长度。 Java 9 中添加的新 List.of 语法通过静态工厂方法在文字语法中定义了一个不可变列表。

    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

    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 时,我们看到它被转储到控制台。

    季节:春季 = [3 月、4 月]

    季节:夏季 = [5 月、6 月、7 月、8 月]

    季节:秋季 = [9 月、10 月]

    季节:冬季 = [11 月、12 月、1 月、2 月]

    组:A = {SPRING=[周二、周四]、FALL=[周二、周四]、夏季=[周一、周二、周三、周四、周五、周六、周日]、冬季=[周二]}

    组:B = {SPRING=[FRIDAY], FALL=[TUESDAY, FRIDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, ThursDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[FRIDAY]}

    组:C = {SPRING=[MONDAY], FALL=[MONDAY, TUESDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, ThursDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[MONDAY]}

    组:D = {SPRING=[WEDNESDAY, FRIDAY], FALL=[FRIDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THRSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[WEDNESDAY]}

    组:E = {SPRING=[TUESDAY], FALL=[TUESDAY, WEDNESDAY], SUMMER=[MONDAY, TUESDAY, WEDNESDAY, THRSDAY, FRIDAY, SATURDAY, SUNDAY], WINTER=[WEDNESDAY]}

    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 周

    了解definition of weekISO 8601 标准可能会对您有所帮助。该标准为“周”赋予了特定含义,并定义了一种文本格式,用于表示特定周或该周中的特定日期。

    为了在 Java 中使用这些周,请考虑将 ThreeTen-Extra 库添加到您的项目中以使用 YearWeek 类。

    LocalDate

    LocalDate 类表示没有时间和时区的仅日期值。

    时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜过后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

    如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。

    continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

    ZoneId z = ZoneId.of( "America/Montreal" ) ;  
    LocalDate today = LocalDate.now( z ) ;
    

    如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的。

    ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
    

    或者指定一个日期。您可以通过数字设置月份,1 月至 12 月的编号为 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-safety

    LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
    

    不可变集合

    上面看到的列表、集合和映射在理想情况下应该是不可变的集合,因为更改这些集合的成员可能会令人困惑和错误。

    新的 Java 9 语法 List.ofMap.of 已经承诺是不可变的。但是,在我们的例子中,Map 理想情况下应该是EnumMap,以提高性能和内存效率。 Map.ofSet.of 的当前实现显然没有检测到枚举作为成员的使用,并通过内部使用 EnumMapEnumSet 自动优化。有一个 OpenJDK issue 开放考虑此类问题:consider enhancements to EnumMap and EnumSet

    获取不可变 EnumSet 和不可变 EnumMap 的一种方法是通过 Google Guava 库:

    每个结果都使用底层EnumSet/EnumMapgetput 等操作会抛出异常。因此,您可以获得与枚举相关的优化以及不变性。

    这里是上面看到的SeasonGroup 类,它们被修改为使用 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.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      【解决方案2】:

      更好的解决方案可能是将所有数据放入数据库中,而不是在源中硬编码或使用属性文件。

      使用数据库会更容易维护,有varietyoffreedatabase引擎可供选择。

      其中两个数据库引擎完全用 Java 实现,只需包含一个 jar 文件即可嵌入到应用程序中。当然,它有点重量级,但它更具可扩展性且更易于维护。仅仅因为今天有 20 条记录并不意味着以后不会因为需求变化或功能蠕变而产生更多记录。

      如果在几周或几个月后,您决定要添加例如一天中的浇水时间限制,那么如果您已经在使用数据库,那么添加该功能会容易得多。即使这从未发生过,您也已经花费了几个小时来学习如何在应用程序中嵌入数据库。

      【讨论】:

        【解决方案3】:

        我支持那些建议在对象中封装函数的人。

        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);
            }
        
        }
        

        编辑:另外,您的日期范围没有考虑闰年:

        我们的季节是这样的:夏天 (5-1 至 8-31) 弹簧 (3-1 至 4-30) 秋季(9-1 至 10-31) 冬季(11-1 至 2-28)

        【讨论】:

          【解决方案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】:

            “日期”是否必须是参数?如果您只是显示当前的浇水时间表,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 为键,然后以 groupToScheduledDays 的 Maps 为值。

            【讨论】:

              【解决方案6】:

              我完全不知道为什么你们中的一些人似乎认为向代码扔大量对象是要走的路。例如,恰好有四个季节,它们不存储任何东西。它如何简化使它们成为对象的任何事情? Wing 说得很对,这些应该是 constants(或者可能是枚举)。

              Bruce 需要的只是一个查找表。他不需要对象和接口的层次结构;他需要一种方法来根据季节和组标识符查找时间表。将事物转化为对象只有在它们具有责任或状态时才有意义。如果两者都没有,那么它们只是标识符,为它们构建特殊对象只会使代码库更大。

              可以构建,例如,Group 对象,每个对象都包含一组时间表字符串(每个季节一个),但如果所有 Group 对象都提供查找功能,那么您以一种不太直观的方式重新发明了查找表。如果他必须查找组,然后查找时间表,那么他所拥有的只是一个两步查找表,这需要更长的编码时间,更有可能出现错误,并且更难维护。

              【讨论】:

                【解决方案7】:

                我同意你绝对应该把这个逻辑放在干净的界面后面:

                public String lookupDays(String group, String date);
                

                但也许您应该将数据粘贴到属性文件中。我不反对在源文件中硬编码这些数据,但正如您所注意到的,Java 在嵌套集合方面可能非常冗长。您的文件可能如下所示:

                A.Summer=M
                A.Spring=tTS
                B.夏天=T

                通常我不喜欢将这样的静态数据移动到外部文件,因为它增加了数据和使用它的代码之间的“距离”。但是,每当您处理嵌套集合,尤其是地图时,事情就会变得非常丑陋,非常快。

                如果你不喜欢这个想法,也许你可以这样做:

                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);
                  }
                
                }
                

                您失去了一些可读性,但至少数据更接近将要使用的位置。

                【讨论】:

                  【解决方案8】:

                  似乎每个人都试图找到 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);
                  ...
                  

                  当然这也可能不对。我会让每个季节成为一个对象,也许每个工作日列表也是一个对象。无论如何,它比试图模仿您的 PHP 代码的笨拙的 Hashtable 更容易重用、理解和扩展。当然,PHP 也有对象,你应该尽可能以类似的方式使用它们,而不是你的超级数组。不过,我确实理解作弊的诱惑。 PHP 让它变得如此简单,如此有趣!

                  【讨论】:

                    【解决方案9】:

                    不要试图像 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 实现,例如HashMapTreeMap

                    【讨论】:

                    • +1 为了清晰起见,我认为用户界面的名称应该重命名为 UserGroup。
                    【解决方案10】:

                    我不是 Java 程序员,但我远离 Java,只是用与语言无关的术语来思考 - 一种更简洁的方法可能是使用常量或枚举类型。这应该适用于任何支持多维数组的语言。

                    如果使用命名常量,例如:

                    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";
                    

                    【讨论】:

                      【解决方案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】:

                        您可以使用 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 不是一种动态语言,它在语言级别上没有散列。

                        注意:您也许可以做一个更好的解决方案,当我读到您的问题时,我突然想到了这一点。

                        【讨论】:

                        • 使用 HashMap 代替 Hashtable 以获得更好的性能。 Hashtable 和 Vector 一样,已经很老了,出于性能原因不应该使用它。主要是因为一切都是同步的,但不应该同步。
                        猜你喜欢
                        • 2015-11-03
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-09-22
                        相关资源
                        最近更新 更多