Java Stream API: изменение значений по критериям - PullRequest
0 голосов
/ 03 апреля 2020

Существует Java класс:

public class Item {
  private String dateModified;
  private Integer color;
}

, где dateModified in format "hh:mm:ss",

и ArrayList<Item> список, который содержит 10 элементов.

Итак, я хочу проверить мой список и:

if now() - dateModified > 1 min , then change color to 1
if now() - dateModified > 5 min , then change color to 2
if now() - dateModified > 10 min, then change color to 3

Как реализовать это с Java Stream API?

ОБНОВЛЕНИЕ: Я реализовал свою задачу в таком коде ниже. Это работает как ожидалось, но кажется огромным и не элегантным. Я забыл сказать, что список должен быть изменяемым.

 list.stream()
 .map(c -> {
  if (compareTime(c.getDateModified(), 600)) {
     c.setColor(3);                       
  } else if (compareTime(c.getDateModified(), 300)) {
     c.setColor(2);
  } else if (compareTime(c.getDateModified(), 60)) {
     c.setColor(1);
  }
     return c;
  }).collect(Collectors.toList());


private boolean compareTime(String dateModified, Integer delta) {
        boolean result = false;
        LocalDateTime now = LocalDateTime.now();
        int hour = now.getHour();
        int minute = now.getMinute();
        int second = now.getSecond();
        Integer secondsDateModified = Integer.parseInt(dateModified.substring(0, 2)) * 3600 +
        Integer.parseInt(dateModified.substring(3, 5)) * 60 +
        Integer.parseInt(dateModified.substring(6, 8)) ;
        Integer secondsNow = hour * 3600 + minute * 60 + second ;
        Integer delta1 = secondsNow - secondsDateModified;
        if ((delta1) > delta) {
            result = true;
        }
        return result;
    }

Любые предложения по улучшению кода приветствуются.

Ответы [ 4 ]

1 голос
/ 03 апреля 2020

Вместо сохранения строки как времени, сохраните объект LocalTime. Кроме того, вместо того, чтобы поменять оригинальный элемент, верните элемент или новый элемент с новым цветом.

  public static class Item {

        private final LocalTime dateModified;

        private final Integer color;

        public Item(LocalTime dateModified, Integer color) {
            this.dateModified = dateModified;
            this.color = color;
        }

        public Item withColor(int color) {
            return new Item(dateModified, color);
        }

        public LocalTime getDateModified() {
            return dateModified;
        }

        public Integer getColor() {
            return color;
        }
    }

Пример

    public static void main(String[] args) {
        List<Item> items = new ArrayList<>(Arrays.asList(
                new Item(LocalTime.parse("10:30:00"), 0),
                new Item(LocalTime.parse("10:30:01"), 255)));

        LocalTime now = LocalTime.now();

        List<Item> modified = items.stream().map(item -> {
            long minutes = Duration.between(item.dateModified, LocalTime.now())
                    .toMinutes();

            return minutes >= 1 ? 
                    item.withColor(minutes >= 10 ? 3 : minutes >= 5 ? 2 : 1) : item;
        }).collect(Collectors.toList());
    }
0 голосов
/ 03 апреля 2020

Во-первых, как сказал Джейсон, не изменяйте свои элементы внутри потоков, делайте копии. ( Чем опасны побочные эффекты в Java 8 Streams? ).

Вам понадобятся промежуточные операции:

long getElapseTimeSinceModification(Item item) {
    return ChronoUnit.MINUTES.between(LocalTime.parse(item.dateModified), LocalDate.now());
}

Optional<Integer> getNewColor(long elapseTimeSinceModification) {
    if (elapseTimeSinceModification > 10) {
        return Optional.of(3);
    } else if (elapseTimeSinceModification > 5) {
        return Optional.of(2);
    } else if (elapseTimeSinceModification > 1) {
        return Optional.of(1);
    }

    return Optional.empty();
}

Item withNewColor(int newColor, Item item) {
    Item newTtem = new Item();
    newTtem.color = newColor;
    newTtem.dateModified = item.dateModified;
    return newTtem;
}

, и тогда вы сможете их применить. в ваш поток:

List<Item> itemsWithNewColor = items.stream()
        .map(item -> getNewColor(getElapseTimeSinceModification(item))
                .map(newColor -> withNewColor(newColor , item))
                .orElse(i))
        .collect(Collectors.toList());
0 голосов
/ 03 апреля 2020

Речь идет о правильной функции сопоставления от разницы минут до чисел.

items.forEach(item -> item.setColor(((int) Math.floor(differenceInMinutes(item.getDateModified(), now) + 5)) / 5));

Обратите внимание, что метод differenceInMinutes возвращает разницу в арифметике с плавающей запятой c.

Выполнены следующие шаги:

  1. Найдите разницу в минутах от даты элементов с помощью now.
  2. Приведите результат к int, который будет работать как Math.floor.
  3. Добавьте 5 к результату.
  4. Разделите на 5.

Так, например, 1,3 минуты приведут к (1 + 5) / 5, равное 1.

9,8 минут, приведет к (9 + 5) / 5, равному 2.

и т. Д.

0 голосов
/ 03 апреля 2020

Как насчет использования отдельных потоков для обновления каждого необходимого диапазона элементов:

public static void updateColor(List<Item> items) {
    final LocalTime now = LocalTime.now();
    final Function<Item, Long> getDurationInMinutes = item -> Duration.between(LocalTime.parse(item.dateModified), now).toMinutes()

    final Predicate<Item> betweenOneAndFive = item -> {
        long duration = getDurationInMinutes.apply(item);
        return duration > ONE && duration <= FIVE;
    };

    final Predicate<Item> betweenFiveAndTen = item -> {
        long duration = getDurationInMinutes.apply(item);
        return duration > FIVE && duration <= TEN;
    };

    final Predicate<Item> greaterThanTen = item -> getDurationInMinutes.apply(item) > TEN;


    items.stream().filter(betweenOneAndFive).forEach(item -> item.color = 1);
    items.stream().filter(betweenFiveAndTen).forEach(item -> item.color = 2);
    items.stream().filter(greaterThanTen).forEach(item -> item.color = 3);
}
...