在期待异常时避免使用空捕获块

Pho*_*reo 6 java exception try-catch date-format control-flow

我正在尝试使用分析日期SimpleDateFormat.由于我的服务采用多种日期格式,我采用了这种方法:

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;
Run Code Online (Sandbox Code Playgroud)

其背后的基本原理try-catch是,如果当前日期格式无法解析dateString,Exception则会抛出一个并且代码将继续循环,直到找到合适的日期格式或返回null.

catch块简直就是有那么该try块将具有以下一些东西(如果没有遵循可能发生编译错误try).

我可以保持代码原样,但空catch块是不好的做法.将来维持其他人也会感到困惑.它简直不优雅.

我可以在catch块中添加以下内容:

catch (Exception e)
{
    if (!(e instanceof ParseException))
    {
        throw e;
    }
}
Run Code Online (Sandbox Code Playgroud)

但同样,内部的代码没有任何意义,因为没有Exception其他的ParseException可以被try块抛出(我NullPointerException在代码的早期检查).使用final块而不是catch块也是没用的.

有没有办法避免空的或无用的catch块?可以try-catch完全避免吗?


类似的问题(但不完全):

避免空的catch子句

空抓块

有一个空的catch语句是否可以?

Men*_*ild 2

到目前为止给出的所有答案都表明您必须忍受异常捕获,但有一些方法可以避免异常。我演示了两种方法,一种使用内置SimpleDateFormatAPI,另一种使用我的库Time4J

简单日期格式

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
}
Run Code Online (Sandbox Code Playgroud)

与 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
      }
}
Run Code Online (Sandbox Code Playgroud)

这种方式是迄今为止解析多种格式最快的方法。自己尝试一下(也可以通过使用版本行 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'”,因为转义输入中的文字“Z”是错误的,除非您明确设置 GMT 时区(零偏移量) ) 在你的SimpleDateFormat- 实例上。背景:ISO-8601 定义了这样的模式,并始终将偏移量 UTC+00:00 分配给文字“Z”。通过转义,您将得到基于错误计算的结果(没有异常或警告)。