Что плохого в моем подходе к созданию списка целых чисел с использованием IntStream и forEach? - PullRequest
0 голосов
/ 07 ноября 2018

Наивный код, который у меня есть:

class ${
    public static void main(String[] _) {
        final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> i++).limit(5).forEach(val -> ints.add(val));
        System.out.println(ints);
    }
}

где я ожидал увидеть в консоли следующее:

[0, 1, 2, 3, 4]

Но на самом деле это:

[0, 0, 0, 0, 0]

Возможно, это что-то очень простое, но чего мне не хватает?

Ответы [ 4 ]

0 голосов
/ 07 ноября 2018

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

final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> {
            System.out.println(i);
            return i++;
        }).limit(5)
                .forEach(val -> ints.add(val));
        System.out.println(ints);

В этом случае значение i всегда будет равно 0, поскольку приращение происходит после того, как значение возвращено, правильный путь -

final List<Integer> ints = new ArrayList<>();
        IntStream.iterate(0, i -> {
            System.out.println(i);
            return ++i;
        }).limit(5)
                .forEach(val -> ints.add(val));
        System.out.println(ints);
0 голосов
/ 07 ноября 2018

i++ имеет значение i перед тем, как увеличивается. Вам необходимо использовать префиксный оператор.

IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));

На самом деле, не делай этого. Нет причин мутировать i, его просто выбрасывают. Используйте бесплатную версию побочного эффекта. В конце концов, в этом вся суть функционального программирования: избегать побочных эффектов.

IntStream.iterate(0, i -> i + 1).limit(5).forEach(val -> ints.add(val));

Для конкретного случая потока последовательных целых чисел вы можете заменить iterate и limit на range:

IntStream.range(0, 5).forEach(val -> ints.add(val));

И, наконец, также было бы лучше собрать поток в список, а не добавлять значения с помощью forEach. Он прямо выражает намерение создать список, что опять-таки позволяет избежать побочных эффектов.

List<Integer> ints = IntStream.range(0, 5).boxed().collect(Collectors.toList());
0 голосов
/ 07 ноября 2018

Вы используете постфикс i++ вместо префикса ++i при передаче значения forEach. Если перейти к следующему, вы получите ожидаемый результат:

IntStream.iterate(0, i -> i + 1).limit(5).forEach(ints::add);

Кроме того, альтернативный способ итерации и объединения лимита с Java9 + использует IntStream.iterate с IntPredicate как:

IntStream.iterate(0, i -> i < 5, i -> i + 1).forEach(ints::add);
0 голосов
/ 07 ноября 2018

Вам необходимо вернуть увеличенное значение. Вы постфикс увеличивали локальную переменную и возвращали неинкрементное значение. Используйте ++i не i++

final List<Integer> ints = new ArrayList<>();
IntStream.iterate(0, i -> ++i).limit(5).forEach(val -> ints.add(val));
System.out.println(ints);

Редактировать См. Пост Джона Кугельмана об использовании немутирующих операций при программировании в функциональном стиле. Использование i + 1 создаст новый примитив и не изменяет переменную параметра.

...