Как сделать стрим из цикла For Loop - PullRequest
1 голос
/ 11 апреля 2019

У меня есть цикл for, который получает значения, передаваемые через аргумент, и, если выполняется определенное условие, он создает новый объект блока. Мне нужно преобразовать этот цикл в поток. Я ищу другие случаи, подобные этому, но так как условие этого цикла - не значение итератора i, а условие даты, я не мог понять, как ограничить поток. Кроме того, элементы не делаются заранее, как в других примерах, но они делаются в процессе. Вот код:

class DateBlock {    
    final Instant from;
    final Instant to;

    DateBlock(Instant from, Instant to) {
        this.from = from;
        this.to = to;
    }

    public static List<DateBlock> blockize(ZonedDateTime fromDate, 
            ZonedDateTime toDate, 
            int blockSize, 
            ChronoUnit blockSizeUnit) {
        List<DateBlock> blocks = new ArrayList<>();
        boolean reachedDate = false;
        for (int i = 0; !reachedDate; i++) {
            ZonedDateTime minDate = fromDate.plus(i * blockSize, blockSizeUnit);
            ZonedDateTime maxDate = fromDate.plus((i + 1) * blockSize, blockSizeUnit);
            reachedDate = toDate.isBefore(maxDate);
            blocks.add(new DateBlock(minDate.toInstant(), maxDate.toInstant()));
        }

        return blocks;
    }
}

Как мне поступить?

1 Ответ

0 голосов
/ 11 апреля 2019

Существует Stream.iterate для итерации по бесконечному потоку, который мы можем использовать для создания элементов из start, которые будут увеличены на blockSize с использованием некоторого ChronoUnit.

Сначала продолжайте генерировать (i + 1) дней в .map(...) и проверьте, равны ли они beforeEnd, затем, если это так, добавьте в список blocks.add, создав new DateBlock(i-1, i). Также используйте allMatch() работу терминала с коротким замыканием, чтобы остановить обработку.

Недостатком здесь является то, что вам нужно проверить beforeEnd 2 раза. В java 9 есть операция .takeWhile, мысль.

ZonedDateTime start = ZonedDateTime.now();
ZonedDateTime end = ZonedDateTime.now().plusDays(5);
Predicate<ZonedDateTime> beforeEnd = date -> date.isBefore(end);
final long blockSize = 1;

List<DateBlock> blocks = new ArrayList<>();
Stream.iterate(start, d -> d.plus(blockSize, ChronoUnit.DAYS))
        .map(d -> d.plus(1, ChronoUnit.DAYS))
        .peek(i -> {
            if(beforeEnd.test(i))
                blocks.add(new DateBlock(i.minus(1, ChronoUnit.DAYS), i));
        })
        .allMatch(beforeEnd);

Запуск, что я получаю даты, как

[DateBlock{from=2019-04-11...,to=2019-04-12..., ..., DateBlock{from=2019-04-15...,to=2019-04-16...}]

UPDATE Я понимаю, что люди говорят, что эта реализация на первый взгляд может показаться неправильной, это только потому, что в java8 нет подходящего метода, просто посмотрите, как элегантно она может выглядеть с .takeWhile методом.

Predicate<DateBlock> beforeEnd = dateBlock -> dateBlock.to.isBefore(end);
Stream.iterate(start, d -> d.plus(blockSize, ChronoUnit.DAYS))
        .map(i -> new DateBlock(i, i.plus(1, ChronoUnit.DAYS)))
        .takeWhile(beforeEnd)
        .collect(Collectors.toList());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...