通过谓词查找第一个元素

本文翻译自:Find first element by predicate

I've just started playing with Java 8 lambdas and I'm trying to implement some of the things that I'm used to in functional languages. 我刚刚开始使用Java 8 lambda,并且正在尝试实现一些我在函数式语言中惯用的东西。

For example, most functional languages have some kind of find function that operates on sequences, or lists that returns the first element, for which the predicate is true . 例如,大多数功能语言都具有某种对序列进行操作的find函数,或者对返回谓词为true的第一个元素的列表进行操作。 The only way I can see to achieve this in Java 8 is: 我看到的在Java 8中实现此目标的唯一方法是:

lst.stream()
    .filter(x -> x > 5)
    .findFirst()

However this seems inefficient to me, as the filter will scan the whole list, at least to my understanding (which could be wrong). 但是,这对我来说似乎效率低下,因为过滤器将扫描整个列表,至少在我看来(可能是错误的)。 Is there a better way? 有没有更好的办法?


#1楼

参考:https://stackoom.com/question/1bQUf/通过谓词查找第一个元素


#2楼

No, filter does not scan the whole stream. 不,过滤器不会扫描整个流。 It's an intermediate operation, which returns a lazy stream (actually all intermediate operations return a lazy stream). 这是一个中间操作,它返回一个惰性流(实际上所有中间操作都返回一个惰性流)。 To convince you, you can simply do the following test: 为了说服您,您只需进行以下测试:

List<Integer> list = Arrays.asList(1, 10, 3, 7, 5);
int a = list.stream()
            .peek(num -> System.out.println("will filter " + num))
            .filter(x -> x > 5)
            .findFirst()
            .get();
System.out.println(a);

Which outputs: 哪个输出:

will filter 1
will filter 10
10

You see that only the two first elements of the stream are actually processed. 您会看到实际上仅处理了流的前两个元素。

So you can go with your approach which is perfectly fine. 因此,您可以采用完全正确的方法。


#3楼

However this seems inefficient to me, as the filter will scan the whole list 但是这对我来说似乎效率低下,因为过滤器将扫描整个列表

No it won't - it will "break" as soon as the first element satisfying the predicate is found. 不,它不会-一旦找到满足谓词的第一个元素,它就会“中断”。 You can read more about laziness in the stream package javadoc , in particular (emphasis mine): 您可以在流包javadoc中阅读有关懒惰的更多信息,尤其是(强调我的):

Many stream operations, such as filtering, mapping, or duplicate removal, can be implemented lazily, exposing opportunities for optimization. 许多流操作(例如过滤,映射或重复删除)可以延迟实施,从而暴露出进行优化的机会。 For example, "find the first String with three consecutive vowels" need not examine all the input strings. 例如,“使用三个连续的元音查找第一个字符串”不需要检查所有输入字符串。 Stream operations are divided into intermediate (Stream-producing) operations and terminal (value- or side-effect-producing) operations. 流操作分为中间(流产生)操作和终端(产生值或副作用)操作。 Intermediate operations are always lazy. 中间操作总是很懒。


#4楼

Unless your list is really huge (thousands of elements), using streams here is just expensive, and even makes the code harder to understand. 除非您的列表确实很大 (成千上万个元素),否则在此处使用流非常昂贵,甚至会使代码难以理解。

Note: java is NOT a functional language (and jvm isn't particularily suited for implementing functional languages efficiently). 注意:java不是一种功能语言(而jvm并不特别适合有效地实现功能语言)。

Much simpler and more efficiant is (on all Iterable's): (在所有Iterable上)更简单,更有效:

for (MyType walk : lst)
    if (walk > 5) { do_whatever; break; }

Or if you wanna skip the iterator: 或者,如果您想跳过迭代器:

for (int x=0; x<list.size(); x++)
    if (list.get(x) > 5 { do_whatever; break; }

Actually, I really wonder why some many people suggest this complex and expensive streams machinery, even for trivial things like getting the first element of an array. 实际上,我真的很奇怪,为什么有人建议使用这种复杂而昂贵的流机制,即使对于诸如获取数组的第一个元素这样的琐碎事情也是如此。 (yes: arrays are still supported in Java8). (是的:Java8仍然支持数组)。


#5楼

return dataSource.getParkingLots().stream().filter(parkingLot -> Objects.equals(parkingLot.getId(), id)).findFirst().orElse(null);

I had to filter out only one object from a list of objects. 我只需要从对象列表中过滤出一个对象。 So i used this, hope it helps. 所以我用了这个,希望对你有帮助。


#6楼

In addition to Alexis C 's answer, If you are working with an array list, in which you are not sure whether the element you are searching for exists, use this. 除了Alexis C的答案外,如果您正在使用数组列表(不确定要搜索的元素是否存在)中,请使用此列表。

Integer a = list.stream()
                .peek(num -> System.out.println("will filter " + num))
                .filter(x -> x > 5)
                .findFirst()
                .orElse(null);

Then you could simply check whether a is null . 然后,您可以简单地检查a是否为null

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值