Exception если в List есть противоречивая дата. Java

У меня есть List<Date>, с датами в формате d/MMMM/yyyy, их нужно обработать, и если есть противоречивая дата(дней больше чем должно быть в месяце), то должно выбрасываться исключение. То есть, если есть: 31/February/2021 То должно выбрасываться исключение. Аргументы метода - строки с годом, днем и месяцев из определенной даты. Вот мой код.

public static boolean checkIfIncorrect(String year, String day, String month) throws ParseException {
        int year2 = Integer.parseInt(year);
        int day2 = Integer.parseInt(day);

        
        Date date = new SimpleDateFormat("MMMM", Locale.ENGLISH).parse(month);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        
        int month2 = cal.get(Calendar.MONTH);

        Calendar calendar = new GregorianCalendar(year2, month2, day2);

        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); 

        if (day2 > daysInMonth) {
            //Тут должно быть выбрасывание ошибки
            System.out.println("Столько дней в дате: " + day2);
            System.out.println("А столько должно быть в дате: " + daysInMonth);
        } else {
            System.out.println("Все хорошо, кол-во дней в дате не превышает возможное");
        }
        return true;
    }
    ```

Ответы (2 шт):

Автор решения: Константин

А в чём вопрос? в месте где у вас написано "//Тут должно быть выбрасывание ошибки" бросайте исключение:

throw new ParseException();

точнее после вывода сообщений в консоль.

→ Ссылка
Автор решения: Alex Rudenko

Поскольку в прошлом вопросе использовалось Stream API, а значит, как минимум Java 8, то и для работы с датами следует применять Java Date/Time API (вводная статья на Medium).

Касаемо формулировки задачи:

У меня есть List<Date>, с датами в формате d/MMMM/yyyy, их нужно обработать, и если есть противоречивая дата(дней больше чем должно быть в месяце), то должно выбрасываться исключение. То есть, если есть: 31/February/2021 То должно выбрасываться исключение.

На самом деле, на входе задан список строк List<String> в определённом формате, которые нужно распарсить и превратить в список дат.

Для парсинга даты в заданном формате существует класс DateTimeFormatter, для которого понадобится установить строгий режим определения даты из строки ResolverStyle.STRICT, тогда в случае некорректной даты будет выбрасываться требуемое исключение DateTimeParseException. Нужно отметить, что это исключение не является checked, и может поэтому использоваться в Stream API.

Также результат можно отсортировать по порядку месяцев, как в прошлом вопросе.

Следует отметить, что yyyy в Java 8 означает год с учётом эры, а простой год обозначается в формате как uuuu.

Поэтому можно либо создать простой форматтер, использующий год uuuu

private static final DateTimeFormatter dMMMMuuuu = DateTimeFormatter
        .ofPattern("d/MMMM/uuuu", Locale.US)
        .withResolverStyle(ResolverStyle.STRICT);

либо (если очень нужен формат yyyy), использовать DateTimeFormatterBuilder, в котором установить "нашу эру" по умолчанию:

private static final DateTimeFormatter dMMMMyyyy = new DateTimeFormatterBuilder()
        .appendPattern("d/MMMM/yyyy")
        .parseDefaulting(ChronoField.ERA, 1) // н.э. / AD
        .toFormatter(Locale.US)
        .withResolverStyle(ResolverStyle.STRICT);
    
public static List<LocalDate> getLocalDateList(List<String> formattedDates) {
    return formattedDates.stream()
        .map(fd -> LocalDate.parse(fd, dMMMMyyyy))
        .sorted(Comparator.comparingInt(LocalDate::getMonthValue)
            .thenComparingInt(LocalDate::getYear)) 
        .collect(Collectors.toList());
}

Тесты:

System.out.println(getLocalDateList(Arrays.asList("30/April/1990", "29/February/2020", "31/February/2000")));
Exception in thread "main" java.time.format.DateTimeParseException: Text '31/February/2000' could not be parsed: Invalid date 'FEBRUARY 31'
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2023)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1958)
    at java.base/java.time.LocalDate.parse(LocalDate.java:430)
    at MyClass.lambda$getLocalDateList$0(MyClass.java:14)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at MyClass.getLocalDateList(MyClass.java:17)
    at MyClass.main(MyClass.java:30)
Caused by: java.time.DateTimeException: Invalid date 'FEBRUARY 31'
    at java.base/java.time.LocalDate.create(LocalDate.java:461)
    at java.base/java.time.LocalDate.of(LocalDate.java:273)
...

Для корректных данных (которые снова форматируются для вывода в исходном формате):

getLocalDateList(Arrays.asList(
    "4/February/2020", "25/May/2021", "8/September/2009", 
    "6/February/1990", "11/April/2012", "30/August/2011"
)).stream().map(dMMMMyyyy::format).forEach(System.out::println);

результат будет таким

6/February/1990
4/February/2020
11/April/2012
25/May/2021
30/August/2011
8/September/2009

Следует заметить, что в строгом режиме названия месяцев должны быть написаны с большой буквы (остальные буквы -- строчные).

→ Ссылка