1

I need to sort a list of String's representing dates.

I tried the following code:

try {
    SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd");
    Collections.sort(days,
            (s1, s2) -> sdf.parse(s1).compareTo(sdf.parse(s2)));
} catch (ParseException e) {
    e.printStackTrace();
}

But in Eclipse I get the compile-time error at sdf.parse(s1):

Unhandled exception type ParseException

Any solution?

My input list is:

[2016-01-02, 2016-01-03, 2016-01-01]
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Fab
  • 1,145
  • 7
  • 20
  • 40
  • Can you not parse them *before* trying to compare? – achAmháin Mar 14 '18 at 11:24
  • 2
    Possible duplicate of [why the ParseException appears when use SimpleDateFormat](https://stackoverflow.com/questions/41058499/why-the-parseexception-appears-when-use-simpledateformat) – Kaustubh Khare Mar 14 '18 at 11:25
  • 4
    If your dates are in the `YYYY-MM-dd` already you can sort them as they are without converting them. – Federico klez Culloca Mar 14 '18 at 11:25
  • Possible duplicate of [How to sort Date which is in string format in java?](https://stackoverflow.com/questions/14451976/how-to-sort-date-which-is-in-string-format-in-java) – Night Programmer Mar 14 '18 at 11:41
  • @SandipND I tried it but list is not sorted – Fab Mar 14 '18 at 11:55
  • Please give us input - probably you have wrong date format in the input data – Maciej Mar 14 '18 at 12:03
  • Possible duplicate of [Java: why can't I throw an exception in Comparator?](https://stackoverflow.com/questions/3832755/java-why-cant-i-throw-an-exception-in-comparator) – Ole V.V. Mar 14 '18 at 12:51
  • I recommend you avoid the `SimpleDateFormat` class. It is not only long outdated, it is also notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). In addition `LocalDate.parse()` will parse your strings without any explicit formatter and isn’t declared to throw any exceptions, so you won’t have your issue. – Ole V.V. Mar 14 '18 at 12:52
  • As an aside, beware of the case of your format pattern letters. `yyyy` and `YYYY` mean different things. Check the documentation if in doubt. – Ole V.V. Mar 14 '18 at 12:53

1 Answers1

7

SimpleDateFormat::parse method throws a checked exception, so you must catch it where the method is called - in this case, inside the lambda expression.

Another problem is that uppercase Y does not represent the year. Check the javadoc: Y is the week year field, which is not always the same as the year. You must change it to lowercase y:

// use lowercase "y" for year
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Collections.sort(days, (s1, s2) -> {
    try {
        return sdf.parse(s1).compareTo(sdf.parse(s2));
    } catch (ParseException e) {
        // what to do when parse fails? just ignore and go on? throw exception?
    }
    return 0; // return something or throw exception?
});

But there are problems with this code: if a ParseException occurs, it means the String doesn't contain a date in the expected format (yyyy-MM-dd). What should you do in this case? Ignore it and return 0 as above (meaning that the invalid string is "equal" to any date?). Stop the sorting and throw an exception?

Maybe it's better to first try to convert the strings to dates (and if you find an invalid string, you can decide to either ignore or stop the conversion), and just after that, when you're sure all elements are valid dates, you sort them.

Java date/time API

As you're using lambdas, your Java version is >= 8, so why not use the new date/time API?

Assuming that days is a collection of String's:

List<LocalDate> sortedDates = days.stream()
    // parse to LocalDate
    .map(LocalDate::parse)
    // sort
    .sorted()
    // get list of LocalDate's
    .collect(Collectors.toList());

In this case, any invalid String in days will make this code throw an exception and the sorting won't be done. The difference is that this method throws an unchecked exception, so you don't need to explicity catch it here, as you did with SimpleDateFormat.

If you want the days list sorted, though, just convert the LocalDate back to String:

days = days.stream()
    // parse to LocalDate
    .map(LocalDate::parse)
    // sort
    .sorted()
    // convert back to string
    .map(LocalDate::toString)
    // get list of String's
    .collect(Collectors.toList());
wthigo
  • 115
  • 4