日期字符串可以由DateTimeFormatter验证而不会捕获异常吗?

时间:2015-07-24 06:07:16

标签: java exception-handling temporal

考虑到通过异常的流量控制被(被许多人)视为反模式,是否可以使用时态库(java.time.*),来验证字符串表示有效日期捕获异常?

考虑以下代码,它依赖于内部爆炸:

public static boolean isValidDateFormat(String date, DateTimeFormatter formatter) {
    try {
        formatter.parse(date);
        return true;
    } catch (DateTimeParseException e) {
        return false;
    }
}

这可以在不发生解析爆炸的情况下实现吗?是否有类似于formatter.isValid(date)的东西(即使内部爆炸 - 这将取决于幕后“JDK impl”)。

1 个答案:

答案 0 :(得分:2)

java.time.format的格式引擎始终使用内部异常来控制流量。如果您尝试使用ParsePosition,情况就是如此。 发生异常,ParsePosition - 对象甚至不报告错误:

   pp = new ParsePosition(0);
   try {
       TemporalAccessor t = 
           DateTimeFormatter.ofPattern("uuuu-MM-dd")
             .withResolverStyle(ResolverStyle.STRICT)
             .parse("2015-02-29", pp);
   } catch (RuntimeException e) {
       e.printStackTrace();
       System.out.println("Error! " + pp);
       // Error! java.text.ParsePosition[index=10,errorIndex=-1]
   }

javadoc解释说:

  

此方法的操作与类似方法略有不同   在java.text.Format上使用ParsePosition。该类将返回错误   使用ParsePosition上的错误索引。相比之下,这种方法   如果发生错误,将抛出DateTimeParseException   包含错误索引的异常。行为的这种变化是   由于解析和解析的复杂性增加所必需的   此API中的日期/时间。

以下示例尝试使用方法parseUnresolved来避免异常:

   ParsePosition pp = new ParsePosition(0);
   try {
        TemporalAccessor t = 
            DateTimeFormatter.ofPattern("uuuu-MM-dd")
             .withResolverStyle(ResolverStyle.STRICT)
             .parseUnresolved("2015-02-29", pp);
        System.out.println("Info! " + t + "/" + pp); // note, no error in pp here!
        // Info! {DayOfMonth=29, MonthOfYear=2, Year=2015},null,null/java.text.ParsePosition[index=10,errorIndex=-1]
        boolean leapyear = Year.from(t).isLeap();
        MonthDay md = MonthDay.from(t);
        if (!leapyear && md.getDayOfMonth() == 29 && md.getMonth().getValue() == 2) {
            System.out.println("Error!"); // hand-made validation covering a special case
        }
   } catch (RuntimeException e) {
        e.printStackTrace(); // does not happen for given input
   }

这种情况无一例外,但您必须自己编写验证码,这会导致问题。

我一直认为这种方法可以将控制程序流程的异常作为错误的编码实践,因此设计了我自己的库Time4J,以便尽可能地避免内部异常(不是在所有情况下都是如此)大多数情况无一例外。)

   ParseLog plog = new ParseLog();
   PlainDate date = ChronoFormatter.ofDatePattern("uuuu-MM-dd", PatternType.CLDR, Locale.ROOT).parse("2015-02-29", plog);
   System.out.println(date); // null
   System.out.println(plog.isError() + "/" + plog.getErrorMessage());
   // true/Validation failed => DAY_OF_MONTH out of range: 29 [parsed={YEAR=2015, MONTH_AS_NUMBER=2, DAY_OF_MONTH=29}]

此代码清楚地展示了另一种设计的可能性。我认为选择java.time的设计是潜在的瓶颈,如果涉及批量处理带有大量错误数据的海量批量数据。