【问题标题】:Can a date string be validated by DateTimeFormatter without catching exception?DateTimeFormatter 可以在不捕获异常的情况下验证日期字符串吗?
【发布时间】:2015-07-24 06:07:15
【问题描述】:

考虑到(许多人)认为通过异常进行的流控制是一种反模式,是否可以使用临时库 (java.time.*) 验证字符串是否代表有效日期,没有 em> 捕捉到异常?

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

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

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

【问题讨论】:

  • 为什么不使用正则表达式?
  • @Daniel 很好,因为不清楚,并且需要额外的编码工作(和测试)。我的问题更多的是“是否存在一些我不知道的隐藏 JDK 库,给定 DateTimeFormatter 确定给定字符串是否有效”
  • 我明白了。我不知道这种有效方法的存在。在 JDK 源代码中使用调试器时找不到任何东西?
  • 也许看看jodatime,它实现了更多关于时间、时间格式和时间解析的功能。它使用较少的异常。 Joda time

标签: java exception-handling temporal


【解决方案1】:

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

   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 的选择设计是潜在的瓶颈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 2021-05-25
    • 1970-01-01
    相关资源
    最近更新 更多