it-roy-ru.com

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++;
});
116
Josh Stone

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

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

Результирующий код аналогичен итерации списка с классическим циклом в стиле i ++ для цикла, за исключением более легкой распараллеливаемости (при условии, конечно, что параллельный доступ только для чтения к параметрам безопасен).

133
srborlongan

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

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

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

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

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

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

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