Java 8 forEach с индексом

Есть ли способ построить метод forEach в Java 8, который выполняет итерацию с индексом? В идеале мне бы хотелось что-то вроде этого:

params.forEach((idx, e) -> query.bind(idx, e));

Лучшее, что я мог сделать сейчас:

int idx = 0;
params.forEach(e -> {
  query.bind(idx, e);
  idx++;
});

Ответ 1

Поскольку вы выполняете итерирование по индексируемой коллекции (списки и т.д.), я полагаю, что вы можете просто перебирать индексы элементов:

IntStream.range(0, params.size())
  .forEach(idx ->
    query.bind(
      idx,
      params.get(idx)
    )
  )
;

Полученный код похож на повторение списка с классическим циклом я ++ - style для цикла, за исключением упрощенной параллелизуемости (при условии, конечно, что одновременный доступ к параметрам доступен только для чтения).

Ответ 2

Он работает с параметрами, если вы захватили массив с одним элементом, который содержит текущий индекс.

int[] idx = { 0 };
params.forEach(e -> query.bind(idx[0]++, e));

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

Если вы работаете с Streams вместо Collections/Iterables, вы должны использовать forEachOder, потому что forEach может выполняться одновременно, и элементы могут выполняться в другом порядке. Следующий код работает как для последовательных, так и для параллельных потоков:

int[] idx = { 0 };
params.stream().forEachOrdered(e -> query.bind(idx[0]++, e));

Ответ 3

Есть обходные пути, но нет чистого/короткого/сладкого способа сделать это с потоками, и, честно говоря, вам, вероятно, будет лучше:

int idx = 0;
for (Param p : params) query.bind(idx++, p);