Determine if a String is a valid date before parsing

后端 未结 12 1649
半阙折子戏
半阙折子戏 2020-12-03 11:36

I have this situation where I am reading about 130K records containing dates stored as String fields. Some records contain blanks (nulls), some contain strings like this: \'

12条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-03 11:52

    See Lazy Error Handling in Java for an overview of how to eliminate try/catch blocks using an Option type.

    Functional Java is your friend.

    In essence, what you want to do is to wrap the date parsing in a function that doesn't throw anything, but indicates in its return type whether parsing was successful or not. For example:

    import fj.F; import fj.F2;
    import fj.data.Option;
    import java.text.SimpleDateFormat;
    import java.text.ParseException;
    import static fj.Function.curry;
    import static fj.Option.some;
    import static fj.Option.none;
    ...
    
    F>> parseDate =
      curry(new F2>() {
        public Option f(String pattern, String s) {
          try {
            return some(new SimpleDateFormat(pattern).parse(s));
          }
          catch (ParseException e) {
            return none();
          }
        }
      });
    

    OK, now you've a reusable date parser that doesn't throw anything, but indicates failure by returning a value of type Option.None. Here's how you use it:

    import fj.data.List;
    import static fj.data.Stream.stream;
    import static fj.data.Option.isSome_;
    ....
    public Option parseWithPatterns(String s, Stream patterns) { 
      return stream(s).apply(patterns.map(parseDate)).find(isSome_()); 
    }
    

    That will give you the date parsed with the first pattern that matches, or a value of type Option.None, which is type-safe whereas null isn't.

    If you're wondering what Stream is... it's a lazy list. This ensures that you ignore patterns after the first successful one. No need to do too much work.

    Call your function like this:

    for (Date d: parseWithPatterns(someString, stream("dd/MM/yyyy", "dd-MM-yyyy")) {
      // Do something with the date here.
    }
    

    Or...

    Option d = parseWithPatterns(someString,
                                       stream("dd/MM/yyyy", "dd-MM-yyyy"));
    if (d.isNone()) {
      // Handle the case where neither pattern matches.
    } 
    else {
      // Do something with d.some()
    }
    

提交回复
热议问题