Как мне перечислить, отобразить и "напечатать, если число> 0" с Java 8/stream API?

Здесь мой код, как сейчас.

List<Cat> cats = petStore.getCatsForSale();

if (!cats.empty) 
    logger.info("Processing for cats: " + cats.size());

for (Cat cat : cats) {
    cat.giveFood();
}

Мой коллега пишет действительно хороший код, используя API потока Java. Я пытался переписать это как одно потоковое утверждение, но я застрял.

petStore.getCatsForSale().stream.forEach(cat -> cat.giveFood)
    .countTheCats().thenDo(logger.info("Total number of cats: " + x)); // Incorrect... is this possible?

Как я могу это сделать? В идеале я хочу одно потоковое выражение...

Ответ 1

Я не уверен, почему вы хотите использовать потоки, поскольку текущие решения цикла работают, но вы также можете использовать Stream<List<Cat>>:

Stream.of(petStore.getCatsForSale())
    .filter(cats -> !cats.isEmpty())
    .flatMap(cats -> {
        logger.info("Processing for cats: " + cats.size());
        return cats.stream();
    })
    .forEach(Cat::giveFood);

Может быть, оптимизация:

Stream.of(petStore.getCatsForSale())
    .filter(cats -> !cats.isEmpty())
    .peek(cats -> logger.info("Processing for cats: " + cats.size()))
    .flatMap(Collection::stream)
    .forEach(Cat::giveFood);

Или используйте этот другой вариант:

Stream.of(petStore.getCatsForSale())
    .filter(cats -> !cats.isEmpty())
    .mapToInt(cats -> {
        cats.forEach(Cat::giveFood);
        return cats.size();
    })
    .findAny()
    .ifPresent(count -> logger.info("Processing for cats: " + count));

Ответ 2

Ваш текущий код намного лучше без потока и может быть сокращен до:

if (!cats.isEmpty()) {
    logger.info("Processing for cats: " + cats.size());
}
cats.forEach(Cat::giveFood); // Assuming giveFood is a stateless operation

Ответ 3

cats.stream()
    .peek(Cat::giveFood)
    .findAny().ifPresent(cat -> logger.info("Processing for cats: " + cats.size()));

Ответ 4

Я согласен с @Lino. Это еще одна альтернатива, основанная на его идее:

List<Cat> cats = petStore.getCatsForSale();

cats.stream().limit(1)
    .flatMap(c -> {
        logger.info("Processing for cats: " + cats.size());
        return cats.stream();
    }).forEach(Cat::giveFood);

Ответ 5

Вы можете использовать этот трюк, это не лучшее решение, и вы возвращаете неиспользованное значение, но оно работает:

petStore.getCatsForSale().stream().peek(Cat::giveFood)
        .findAny() // the trick
        .orElseGet(() -> {
            System.out.println("Cats" + count); // your log
            return null; // will be ignored
        });