我正在尝试使用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流代码)。在性能方面的改进是巨大的。而且代码也是线程安全的。

有关格式格式的一般说明
  • 我担心看到模式“yyyy-MM-dd'T'HH:mm:ss.SSS-hh:mm”,因为“h”代表12小时制(因此缺少AM / PM !!! )。
  • 我也担心看到模式“yyyy-MM-dd'T'HH:mm:ss.SSS'Z'”,因为除非明确设置了GMT-Zone(零),否则在输入中转义文字“Z”是错误的偏移量)在您的SimpleDateFormat -instance上。背景:ISO-8601定义了这种模式,并始终将偏移量UTC + 00:00分配给文字“Z”。通过转义,您将获得基于错误计算的结果(无异常或警告)。
  • 07-24 09:43
    查看更多