java类中的静态最终日期字段

java类中的静态最终日期字段,java,java.util.date,Java,Java.util.date,我们有一个公共的静态util方法,它可以解析字符串并返回日期对象,但如果解析的字符串无法转换为日期对象,它也会抛出ParseException 现在,在另一个类中,我希望使用上面描述的util方法将静态最终日期初始化为一个值。但鉴于util方法引发ParseException,这是不允许的 这是我想做的,这是不允许的 public static final MY_DATE = Util.getDateFromString('20000101'); 建议使用什么方法来保持此日期字段为“final

我们有一个公共的静态util方法,它可以解析字符串并返回日期对象,但如果解析的字符串无法转换为日期对象,它也会抛出ParseException

现在,在另一个类中,我希望使用上面描述的util方法将静态最终日期初始化为一个值。但鉴于util方法引发ParseException,这是不允许的

这是我想做的,这是不允许的

public static final MY_DATE = Util.getDateFromString('20000101');
建议使用什么方法来保持此日期字段为“final”?

您可以使用静态初始值设定项块:

public static final Date MY_DATE;

static {
    try {
       MY_DATE = Util.getDateFromString("20000101");
    } catch (ParseException e) {
       // Whatever you want to do here. You might want to throw
       // an unchecked exception, or you might want to use some fallback value.
       // If you want to use a fallback value, you'd need to use a local
       // variable for the result of parsing, to make sure you only have a
       // single assignment to the final variable.
    }
}
不过,我建议不要这样做
Date
是一种可变类型-通过公共静态final变量公开它是个坏主意

从Java 8开始,
Java.time
包最适合用于几乎所有的日期/时间工作,您可以编写:

public static final LocalDate START_OF_JANUARY_2000 = LocalDate.of(2000, 1, 1);
在Java8之前,我建议您使用它,它有许多不可变的日期/时间类型,并且是处理日期和时间的更好的库。看起来您希望:

public static final LocalDate START_OF_JANUARY_2000 = new LocalDate(2000, 1, 1);

请注意,即使您决定使用
java.util.Date
,在我的视图中解析字符串也没有多大意义——您知道数值,为什么不直接以这种方式提供它们呢?如果您没有合适的方法从年/月/日(可能应用了合适的时区)构造一个日期,那么您可以轻松地编写一个日期。

OMG!我终于可以用一个更好、更精英、更优雅的答案来完成Jon Skeet

一种简洁的方法是使用匿名类和实例块,如下所示:

public static final Date MY_DATE = new Date() {{
    try {
        setTime(Util.getDateFromString("20000101").getTime());
    } catch (ParseException e) {
        throw new RuntimeException(e);
    }
}};
public static final Date MY_DATE = getDateFromStringWithoutExploding("20000101");

private static Date getDateFromStringWithoutExploding(String dateString) {
    try {
        return Util.getDateFromStringWithoutExploding(dateString);
    catch(ParseException e) {
        throw new IllegalArgumentException(e);
    }
}
这是因为(很明显)
java.util.Date
不是不变的

要使日期不可变,从而在设计方面更易于接受,请重写setter方法:

public static final Date MY_DATE = new Date() {{
        try {
            super.setTime(Util.getDateFromString("20000101").getTime());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    // Formatted for brevity :)
    @Override public void setYear(int year) { throw new UnsupportedOperationException();}
    @Override public void setMonth(int month) {throw new UnsupportedOperationException();}
    @Override public void setDate(int date) {throw new UnsupportedOperationException();}
    @Override public void setHours(int hours) {throw new UnsupportedOperationException();}
    @Override public void setMinutes(int minutes) {throw new UnsupportedOperationException();}
    @Override public void setSeconds(int seconds) {throw new UnsupportedOperationException();}
    @Override public void setTime(long time) {throw new UnsupportedOperationException();}
};

另一种方法是,如果您确定不会实际获取声明的异常,则创建另一个方法(本地或在Util中),将ParseException包装到未检查的异常中,如下所示:

public static final Date MY_DATE = new Date() {{
    try {
        setTime(Util.getDateFromString("20000101").getTime());
    } catch (ParseException e) {
        throw new RuntimeException(e);
    }
}};
public static final Date MY_DATE = getDateFromStringWithoutExploding("20000101");

private static Date getDateFromStringWithoutExploding(String dateString) {
    try {
        return Util.getDateFromStringWithoutExploding(dateString);
    catch(ParseException e) {
        throw new IllegalArgumentException(e);
    }
}

这是合理的,并且实际上反映了正在发生的事情-您知道您传递的日期字符串是可以的,所以try-catch是敷衍性的。

它已在注释中说明,但为了更明确:

public static final MY_DATE = new GregorianCalendar(2000, 1, 1).getTime();

只有当您可以使用分配给公共静态final的可变日期时,才可以执行此操作。

这不会使用'final'关键字编译。只有当我们删除“final”时,它才会编译,而这正是我们当前代码中的内容。但是您的第二个建议是从年/月/日创建日期,这似乎是合理的。谢谢。@Ramesh:如果您让
catch
块抛出一个
运行时异常来指示意外的失败,它应该使用
final
进行编译。但最好还是不要从一个可能引发异常的初始值设定项开始…util方法来自一个我们无权更改签名的库。我同意您的最后一个建议,即直接使用GregorianCalendar的构造函数初始化日期,类似于public static final date=new GregorianCalendar(2000,0,1).getTime()@拉梅什:这将使用默认的系统时区-这真的是你想要的吗?(它也给你留下了一个可变的
日期
。我真的非常鼓励你选择Joda Time。)@Ramesh,
日期
是可变的,
final
只需防止它被重新分配,但值仍然可以更改。公共静态字段中的可变是非常不受欢迎的。我的回答建议使用Joda Time,它具有不可变的类型,并且是一个更好的库:)@Jonsket哦,来吧。。。你一定会喜欢1337的工作:)事实上,joda和静态实例块的结合可能是最好的选择。顺便说一句,我向你脱帽致敬——一个人能得到多少徽章!?你是一个徽章和代表工厂!谢谢波希米亚人+1用于DBI(双大括号初始化)方法。但是现在我将使用Jon提到的最后一个建议,我可以说我的日期=新的Gregoriacalendar(2000,0,1).getTime();