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

2022-09-04 23:02:24

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

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

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

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


答案 1

java.time.format 的格式引擎始终使用内部异常来控制流。如果您尝试使用 .发生异常,并且 -object 甚至不报告错误:ParsePositionParsePosition

   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


答案 2

推荐