在某些列表中编号,Java Streams foreach

时间:2015-12-06 14:21:34

标签: java foreach java-stream

我想在一些数组(可能包含随机位置中的空元素)上编写foreach,它将打印到带有编号的非空元素的控制台列表

假设我有一个名为personArray的数组,其中包含一些Person对象。我期望的结果是这样的

1 Name Lastname
2 Name2 Lastname2
3 Name3 Lastname3
and so on..

我知道我可以这样做:

Arrays.stream(personArray).filter(n -> n != null).forEach(person -> System.out.print(person.getName() + " " + person.getLastname()));

但是这将打印非订货号

的非空对象
Name Lastname
Name2 Lastname2
Name3 Lastname3
and so on..

所以如何"数字"它?因为在lambda声明的外部使用的每个变量必须是最终的,否则不可能增加它

3 个答案:

答案 0 :(得分:2)

可能不是最好的解决方案,但它只是一个

    AtomicInteger x=new AtomicInteger(1);
    Arrays.stream(personArray)
    .filter(n -> n != null)
    .forEach(person -> System.out.print((x.getAndIncrement())+""+person.getName() + " " + person.getLastName()));

如果您使用AtomicInteger可以接受,则可以执行此操作,AtomicInteger为不可变类。

或者没有使用任何变量,与reduce

一起玩
    Arrays.stream(personArray)
    .filter(n -> n != null)
    .reduce(1,(a,b)->{System.out.println(a+" "+b.getName() + " " + b.getLastName());return ++a;},(a,b)->{return ++a;});

请注意,在lambda表达式中,您不允许修改对象,但您可以修改其状态。这就是为什么在我的第一个示例中,您无法使用x关键字向new重新提供新值,但您可以修改其状态,即包装的整数。

答案 1 :(得分:2)

不会产生新的副作用且不滥用API的解决方案是创建索引流:

IntStream.range(0, personArray.length)
         .map(idx -> (idx+1) + " " + personArray[idx].getName() + " " +
                     personArray[idx].getLastname())
         .forEach(System.out::println);

还有一些第三方库允许您表示索引值对的流。其中一个库是StreamEx

EntryStream.of(personArray) // creates stream of Entry<Integer, Person>
           .mapKeys(idx -> idx+1) // Add one to indices
           .mapKeyValue((idx, person) -> idx+" "+person.getName()+" "+ person.getLastname())
           .forEach(System.out::println);

答案 2 :(得分:1)

有一个简单的技巧可以避免这个问题。 让我们创建一个大小为1的int数组。

int[] number = {1};

然后在打印时,您可以像

一样使用它
System.out.println((number[0]++) + " ...");

以下是一个工作示例:

int[] number = {1};
Arrays.stream(personArray)
    .filter(n -> n != null)
    .forEachOrdered(person -> System.out.println(
        (number[0]++) + ". " +person.getName() + " " + person.getLastname()
    ));

请注意,我已将print替换为println。 我还将forEach更改为forEachOrdered,因为前者并不保证能够保持相遇顺序。