如何在java 8中获取findFirst()的索引?

问题描述 投票:0回答:4

我有以下代码:

ArrayList <String> entries = new ArrayList <String>();

entries.add("0");
entries.add("1");
entries.add("2");
entries.add("3");

String firstNotHiddenItem = entries.stream()
                    .filter(e -> e.equals("2"))
                    .findFirst()
                    .get();

我需要知道第一个返回元素的索引是什么,因为我需要在条目内编辑它

ArrayList
。据我所知
get()
返回元素的值,而不是引用。我应该只使用

int indexOf(Object o)

相反?

java java-8 java-stream
4个回答
20
投票

您可以使用

IntStream
获取元素的索引,例如:

int index = IntStream.range(0, entries.size())
                     .filter(i -> "2".equals(entries.get(i)))
                     .findFirst().orElse(-1);

但是你应该使用

List::indexOf
方法,这是首选方法,因为它更简洁,更具表现力,并且计算出相同的结果。


8
投票

您不能以简单的方式 - 流在没有上下文的情况下处理元素在流中的位置。

但是,如果您准备脱掉手套......

int[] position = {-1};

String firstNotHiddenItem = entries.stream()
        .peek(x -> position[0]++)  // increment every element encounter
        .filter("2"::equals)
        .findFirst()
        .get();

System.out.println(position[0]); // 2

使用

int[]
,而不是简单的
int
,是为了规避“有效最终”的要求;数组的引用常量,只有其内容发生变化。

还要注意使用方法引用

"2"::equals
而不是lambda
e -> e.equals("2")
,这不仅避免了可能的NPE(如果流元素是
null
),更重要的是看起来way更酷。


更美味(更少恶意)的版本:

AtomicInteger position = new AtomicInteger(-1);

String firstNotHiddenItem = entries.stream()
        .peek(x -> position.incrementAndGet())  // increment every element encounter
        .filter("2"::equals)
        .findFirst()
        .get();

position.get(); // 2

1
投票

这将适用于 Java 8 或更高版本的 Eclipse Collections

int firstIndex = ListIterate.detectIndex(entries, "2"::equals);

如果使用

MutableList
,可以将代码简化如下:

MutableList<String> entries = Lists.mutable.with("0", "1", "2", "3");
int firstIndex = entries.detectIndex("2"::equals);

还有一个方法可以找到最后一个索引。

int lastIndex = entries.detectLastIndex("2"::equals);

注意:我是 Eclipse Collections 的提交者


0
投票

是的,您应该使用

indexOf("2")
来代替。您可能已经注意到,任何基于流的解决方案都具有更高的复杂性,但没有提供任何好处。

在这种特定情况下,性能没有显着差异,但过度使用流可能会导致性能急剧下降,例如当使用

map.entrySet().stream().filter(e -> e.getKey().equals(object)).map(e -> e.getValue())
而不是简单的
map.get(object)
时。

集合操作可以利用其已知的结构,而大多数流操作意味着线性搜索。所以正版收藏运营更可取。

当然,如果没有集合操作,例如当您的谓词不是简单的相等测试时,Stream API 可能是正确的工具。如“Java 8 中是否有一种简洁的方法来迭代带有索引的流?”中所示,任何涉及索引的任务的解决方案都可以使用索引作为起点,例如通过

IntStream.range
,并通过
List.get(int)
访问列表。如果源不是数组或随机访问
List
,则没有同样干净且有效的解决方案。有时,循环可能是最简单、最有效的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.