Java8StreamAPI 查找与属性值匹配的唯一对象

使用 Java8流查找与 Collection 中的 Property 值匹配的对象。

List<Person> objects = new ArrayList<>();

个人属性-> 姓名,电话,电子邮件。

遍历人员列表并找到匹配电子邮件的对象。 看到这可以通过 Java8流很容易地完成。但是那仍然会返回一个集合?

例如:

List<Person> matchingObjects = objects.stream.
filter(p -> p.email().equals("testemail")).
collect(Collectors.toList());

但我知道它总是有一个独特的对象。我们能不能做点什么来代替 Collectors.toList这样我就可以直接得到实际的物体。而不是获取对象列表。

226090 次浏览

Instead of using a collector try using findFirst or findAny.

Optional<Person> matchingObject = objects.stream().
filter(p -> p.email().equals("testemail")).
findFirst();

This returns an Optional since the list might not contain that object.

If you're sure that the list always contains that person you can call:

Person person = matchingObject.get();

Be careful though! get throws NoSuchElementException if no value is present. Therefore it is strongly advised that you first ensure that the value is present (either with isPresent or better, use ifPresent, map, orElse or any of the other alternatives found in the Optional class).

If you're okay with a null reference if there is no such person, then:

Person person = matchingObject.orElse(null);

If possible, I would try to avoid going with the null reference route though. Other alternatives methods in the Optional class (ifPresent, map etc) can solve many use cases. Where I have found myself using orElse(null) is only when I have existing code that was designed to accept null references in some cases.


Optionals have other useful methods as well. Take a look at Optional javadoc.

Guava API provides MoreCollectors.onlyElement() which is a collector that takes a stream containing exactly one element and returns that element.

The returned collector throws an IllegalArgumentException if the stream consists of two or more elements, and a NoSuchElementException if the stream is empty.

Refer the below code for usage:

import static com.google.common.collect.MoreCollectors.onlyElement;


Person matchingPerson = objects.stream
.filter(p -> p.email().equals("testemail"))
.collect(onlyElement());

findAny & orElse

By using findAny() and orElse():

Person matchingObject = objects.stream().
filter(p -> p.email().equals("testemail")).
findAny().orElse(null);

Stops looking after finding an occurrence.

findAny

Optional<T> findAny()

Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. This is a short-circuiting terminal operation. The behavior of this operation is explicitly nondeterministic; it is free to select any element in the stream. This is to allow for maximal performance in parallel operations; the cost is that multiple invocations on the same source may not return the same result. (If a stable result is desired, use findFirst() instead.)

You can use the method .reduce() instead .get() or .orElseGet(). That will help you to avoid NoSuchElementException and NullPointerException

Person matchingObject = objects.stream()
.filter(p -> p.email().equals("testemail"))
.reduce(DefaultObjectReturned, (a1, resultAsPerson) -> resultAsPerson);