0
votes

I know, there are many examples how to remove something from a list while iterating over it, but thats not the point.

I'm trying to automatize a process that I need to document my work (in the end it should be printing into a document something like that 01.01.2019 - Tuesday). For that I have a UI with two datepicker. After selecting two different dates and comparing them I know how many days are between these dates.

Now the following problem:

I'm adding all days between the two dates in a list. After that I'm trying to block some specific days (always the same days: Monday, Saturday and Sunday). These are days that shouldn't be in the list anymore.

I tried things like removing the value out of the list while I'm iterating over it. But it doesn't work the way I expect it to.

Example:

I'm selecting the 17.09.2019 as beginning and 24.09.2019 as end. The expected output should be:

Weekday: TUESDAY
Date: 2019-09-18
Weekday: WEDNESDAY
Date: 2019-09-19
Weekday: THURSDAY
Date: 2019-09-20
Weekday: FRIDAY
Date: 2019-09-24
Weekday: TUESDAY

but if I run my code the output is:

Weekday: TUESDAY
Date: 2019-09-18
Weekday: WEDNESDAY
Date: 2019-09-19
Weekday: THURSDAY
Date: 2019-09-20
Weekday: FRIDAY
Date: 2019-09-21
Weekday: FRIDAY
Date: 2019-09-22
Weekday: FRIDAY
Date: 2019-09-23
Weekday: FRIDAY
Date: 2019-09-24
Weekday: TUESDAY

You can see it. The word Saturday, Sunday and Monday will get removed but it's still in the list.

Code:

long daysBetween = ChronoUnit.DAYS.between(dateBeginPicker.getValue(), dateEndPicker.getValue());
                int db = Math.toIntExact(daysBetween);

                String day = "";
                List<LocalDate> dateList = new ArrayList<>();
                LocalDate dateAfter = null;

                for (int i = 0; i <= db; i++) {
                    dateAfter = dateBeginPicker.getValue().plusDays(i);
                    dateList.add(dateAfter);
                }

                for (Iterator<LocalDate> iterator = dateList.iterator(); iterator.hasNext();) {
                    LocalDate date = iterator.next();

                    if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY) || date.getDayOfWeek().equals(DayOfWeek.SUNDAY) || date.getDayOfWeek().equals(DayOfWeek.MONDAY)) {
                        iterator.remove();
                        dateList.remove(date);
                    }
                    else {
                        day = date.getDayOfWeek().toString();
                    }

                    System.out.println("Date: " + date);
                    System.out.println("Weekday: " + day);
                }

What I expecting in the end is, that the every monday, saturday and sunday should removed out of the list, and the output should be correct (as in my example).

Thank you

2
Note that a switch could make the code a bit easier to read: switch(date.getDayOfWeek()) { case SATURDAY: case SUNDAY: case MONDAY: /* if body */ break; default: /* else body */} Furthermore you can use == to compare enum constants. Also consider using removeIf... - fabian

2 Answers

3
votes

You have your System.out.println() commands within the for-loop, but outside of the else-block. That's why all of the dates are displayed.

Just move those two lines inside the else-block and you will get the output you want.

3
votes

I am glad that you solved your problem. I would like to add three minor points.

  1. You may use a stream if you like.
  2. You should not call remove both on the Iterator and on the List.
  3. My explanation of what went wrong in your code.

1. You may use a stream. It’s easiest in Java 9 and later:

    LocalDate begin = LocalDate.of(2019, Month.SEPTEMBER, 17);
    LocalDate end = LocalDate.of(2019, Month.SEPTEMBER, 24);

    final Set<DayOfWeek> blockedDays = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
    List<LocalDate> dateList = begin.datesUntil(end.plusDays(1))
            .filter(ld -> ! blockedDays.contains(ld.getDayOfWeek()))
            .collect(Collectors.toList());

    dateList.forEach(ld -> {
        System.out.println(ld.getDayOfWeek());
        System.out.println(ld);
    });

Output is:

TUESDAY
2019-09-17
WEDNESDAY
2019-09-18
THURSDAY
2019-09-19
FRIDAY
2019-09-20
TUESDAY
2019-09-24

2. Don’t call dateList.remove(). Your call to iterator.remove() has already removed the date from the list. So your call to dateList.remove() does nothing. Which is a luck. If it had found an element to remove, the Iterator would have thrown a ConcurrentModificationException on the subsequent call to hasNext(). You are not allowed to modify a collection while iterating over it except through the iterator, and the result of trying to do it is undefined. So delete that call from your code.

3. What went wrong in your code? Your output looks funny. For the blocked days FRIDAY is printed along with the date, that is, the day of week and the date don’t match. What happened was: You correctly set date to the date from the list. Since the day was a blocked day, you executed the if part of the if statement, removing the date from the list. You did not execute the else part, so day is unchanged from the previous iteration, where it was FRIDAY. After the if statement you unconditionally printed date, the blocked date (2019-09-21, 2019-09-22 and 2019-09-23 in turn), and day (FRIDAY each time).