问题
We've a public static util method which can parse a string and return a Date object, but it also throws ParseException in case the string parsed cannot be converted to a Date object.
Now, in another class I would like to have a static final Date initialized to a value using the util method described above. But given that the util method throws ParseException, this is not allowed.
This is what I want to do, which is not allowed
public static final MY_DATE = Util.getDateFromString('20000101');
What is the recommended way to keep this Date field 'final'?
回答1:
Well you could use a static initializer block:
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.
}
}
However, I would advise against this. Date
is a mutable type - exposing it via a public static final variable is a bad idea.
As of Java 8, the java.time
package is the most appropriate to use for almost all date/time work, where you'd write:
public static final LocalDate START_OF_JANUARY_2000 = LocalDate.of(2000, 1, 1);
Prior to Java 8, I'd recommend that you use Joda Time which has many immutable date/time types - and is a thoroughly better library for working with dates and times. It looks like you'd want:
public static final LocalDate START_OF_JANUARY_2000 = new LocalDate(2000, 1, 1);
Note that even if you do decide to go with java.util.Date
, it doesn't make much sense to parse the string in my view - you know the values numerically, so why not just supply them that way? If you haven't got a suitable method to construct a Date
from a year / month / day (presumably applying an appropriate time zone) then you could easily write one.
回答2:
OMG! I finally get to out-do Jon Skeet with a better, more elite, more elegant answer!
One neat way is to use an anonymous class, with an instance block, like this:
public static final Date MY_DATE = new Date() {{
try {
setTime(Util.getDateFromString("20000101").getTime());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}};
This works because (remarkably) java.util.Date
is not immutable!
To make the Date immutable, and therefore more acceptable design-wise, override the setter methods too:
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();}
};
回答3:
Another way, if you're sure you won't actually get the declared exception, is to create another method, either locally or in Util, that wraps the ParseException in an unchecked exception, like this:
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);
}
}
This is reasonable, and actually reflects what's going on anyway - you know the date string you are passing in is OK, so the try-catch is perfunctory.
回答4:
It's been stated in a comment, but to make it more explicit:
public static final MY_DATE = new GregorianCalendar(2000, 1, 1).getTime();
Do this only if you can live with a mutable date assigned to a public static final.
来源:https://stackoverflow.com/questions/8471063/static-final-date-field-in-a-java-class