我正在尝试使用SimpleDateFormat
解析日期。由于我的服务采用多种日期格式,因此我采用了this方法:
String[] formats = {
"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
"yyyy-MM-dd'T'HH:mm:ss.SSS-HH:mm",
"EEE MMM dd HH:mm:ss Z yyyy"};
for (String format : formats)
{
try
{
return new SimpleDateFormat(format).parse(dateString);
}
catch (ParseException e) {}
}
return null;
try-catch
的基本原理是,如果当前日期格式无法解析dateString
,则将引发Exception
,并且该代码将继续循环直到找到合适的日期格式,或返回null
。catch
块就在那里,因此try
块后面会有一些东西(如果try
之后没有任何内容,则会发生编译错误)。我可以按原样保留代码,但是空的
catch
块是不好的做法。将来其他人继续维护也将造成混乱。而且这简直就是优雅。我可以将以下内容放入
catch
块:catch (Exception e)
{
if (!(e instanceof ParseException))
{
throw e;
}
}
但是同样,里面的代码没有其他用途,因为
Exception
块可能会抛出ParseException
(我在代码的前面检查了try
)。使用NullPointerException
块代替final
块也是没有用的。有没有办法避免空或无用的
catch
块?可以完全避免catch
吗?类似问题(但不完全相同):
Avoiding an empty catch clause
Empty catch blocks
Is it ever ok to have an empty catch statement?
最佳答案
到目前为止,所有给出的答案都表明您必须忍受异常捕获,但是有一些方法可以避免出现异常。我演示了两种方法,一种使用内置的SimpleDateFormat
-API,另一种使用我的库Time4J。
SimpleDateFormat
private static final List<SimpleDateFormat> SDF_FORMATS;
static {
String[] formats =
{
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ss.SSS-HH:mm",
"EEE MMM dd HH:mm:ss Z yyyy"
};
SDF_FORMATS =
Arrays.stream(formats)
.map(pattern -> new SimpleDateFormat(pattern, Locale.ENGLISH))
.collect(Collectors.toList());
}
public static java.util.Date parse(String input) {
for (SimpleDateFormat sdf : SDF_FORMATS) {
ParsePosition pos = new ParsePosition(0);
java.util.Date d = sdf.parse(input, pos);
if (pos.getErrorIndex() == -1) {
return d;
}
}
// log an error message
return null; // or throw an exception
}
尽管与try-catch-code相比不是非常引人注目,但仍可观察到性能改进。但是,需要注意的一个重要问题是,此呈现的代码是而非线程安全的。为了在多线程环境中使用,您必须始终实例化
SimpleDateFormat
的新实例,或者可以尝试使用ThreadLocal
最小化此类实例化。时间4J
private static final MultiFormatParser<Moment> MULTI_FORMAT_PARSER;
static {
String[] formats =
{
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ss.SSS-HH:mm",
"EEE MMM dd HH:mm:ss Z yyyy"
};
List<ChronoFormatter<Moment>> formatters =
Arrays.stream(formats)
.map(pattern ->
ChronoFormatter.ofMomentPattern(
pattern,
PatternType.CLDR,
Locale.ENGLISH,
Timezone.ofSystem().getID()))
.collect(Collectors.toList());
MULTI_FORMAT_PARSER = MultiFormatParser.of(formatters);
}
public static java.util.Date parse(String input) {
ParseLog plog = new ParseLog();
Moment m = MULTI_FORMAT_PARSER.parse(input, plog);
if (plog.isError()) {
// log an error message based on plog.getErrorMessage()
return null; // or throw an exception
} else {
return TemporalType.JAVA_UTIL_DATE.from(m); // converted to old API
}
}
到目前为止,这种方法是解析多种格式的最快方法。自己尝试一下(也可以通过版本3.x在Java-6或Android上使用Time4J,但随后必须在静态初始值设定项中调整Java-8流代码)。在性能方面的改进是巨大的。而且代码也是线程安全的。
有关格式格式的一般说明
SimpleDateFormat
-instance上。背景:ISO-8601定义了这种模式,并始终将偏移量UTC + 00:00分配给文字“Z”。通过转义,您将获得基于错误计算的结果(无异常或警告)。