我想在一些数组(可能包含随机位置中的空元素)上编写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声明的外部使用的每个变量必须是最终的,否则不可能增加它
答案 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
,因为前者并不保证能够保持相遇顺序。