Java如何对对象内部的列表进行流操作?

huangapple go评论72阅读模式
英文:

Java how to stream a list inside a list for an object?

问题

所以我在另一个列表中存储了一些列表。
而在这些列表内部,有不同的对象。
我想根据属性获取特定的对象。

Human robert = building.getRoomList()
    .stream()
    .filter(room -> room.getEmployeeList()
         .stream()
         .filter(human -> human.getName().equals("Robert")))
    .findFirst().get();

为什么它不起作用呢?

英文:

So I have lists stored inside of another list.
And inside of that lists there a different objects.
I want to get a specific object based on an attribute.

Human robert = building.getRoomList()
    .stream()
    .filter(room -> room.getEmployeeList()
         .stream()
         .filter(human -> human.getName().equals("Robert")))
    .findFirst().get();

Why doesn't it work?

答案1

得分: 2

尝试一下这样写:

Human robert = building.getRoomList().stream()
    .map(Room::getRoomList)
    .flatMap(Collection::stream)
    .filter(human -> human.getName().equals("Robert"))
    .findFirst()
    .orElseThrow(() -> new RuntimeException("找不到Robert!"));
英文:

Try this:

Human robert = building.getRoomList().stream()
    .map(Room::getRoomList)
    .flatMap(Collection::stream)
    .filter(human -> human.getName().equals("Robert"))
    .findFirst()
    .orElseThrow(() -> new RuntimeException("Robert not found!"));

答案2

得分: 1

你可以使用 Stream.flatMap 来实现:

Optional<Human> robert = building.getRoomList().stream()
    .flatMap(room -> room.getEmployeeList().stream())
    .filter(human -> human.getName().equals("Robert"))
    .findFirst();

robert.ifPresent(r -> /* 对 Robert 做一些操作 */);

`Stream.flatMap` 将每个 `room` 映射为一个 `human`返回的流由所有房间中的所有人组成被平铺即不作为子列表或子流)。
英文:

You can do it using Stream.flatMap:

Optional&lt;Human&gt; robert = building.getRoomList().stream()
    .flatMap(room -&gt; room.getEmployeeList().stream())
    .filter(human -&gt; human.getName().equals(&quot;Robert&quot;))
    .findFirst();

robert.ifPresent(r -&gt; /* do something with Robert */);

Stream.flatMap maps each room to a stream of humans and the returned stream consists of all the humans of all the rooms, flattened (i.e. not as sublists or substreams).

答案3

得分: 1

为什么它不起作用?

Stream::filter 需要一个 Predicate<T>,并返回相同的 Stream<T>。只要你在 filter 中嵌套了另一个 filter,这永远不会起作用,因为外部一个需要 Predicate<T>,而内部一个返回的是明显不兼容的 Stream<T>

你可能想使用 flatMap

Human robert = building.getRoomList()
    .stream()                                     
    .flatMap(room -> room                         
        .getEmployeeList()                        
        .stream()                                 
        .filter(human -> human.getName()          
                              .equals("Robert"))) 
    .findFirst()                                  
    .orElse(null);                                

请记住,谓词 human -> human.getName().equals("Robert") 既不是对空值安全的,也不是对其名称为 null 的情况安全的。为了空值安全,可以这样使用 flatMap:

    .flatMap(room -> room.getEmployeeList()
                         .stream()
                         .filter(Objects::nonNull)
                         .filter(human -> "Robert".equals(human.getName())))
英文:

> Why doesn't it work?

Stream::filter requires a Predicate&lt;T&gt; and returns the very same Stream&lt;T&gt;. As long as you nest filter in filter, this would never work because the outer one requires Predicate&lt;T&gt; while the inner one returns Stream&lt;T&gt; which is clearly not compatible.

You might want to use flatMap:

Human robert = building.getRoomList()
    .stream()                                     // Stream&lt;Room&gt;
    .flatMap(room -&gt; room                         // Stream&lt;Human&gt; flatmapped from:
        .getEmployeeList()                        // .. for each Room get List&lt;Human&gt;
        .stream()                                 // .. for each Room have Stream&lt;Human&gt;
        .filter(human -&gt; human.getName()          // .. for each Room keep the one named
                              .equals(&quot;Robert&quot;))) // .. Robert
    .findFirst()                                  // find the first Robert, the Human 
    .orElse(null);                                // or result in null

Remember the predicate human -&gt; human.getName().equals(&quot;Robert&quot;)) is not null-safe neither when human is null nor when its name is null. For the null-safety, flat-map like this:

    .flatMap(room -&gt; room.getEmployeeList()
                         .stream()
                         .filter(Objects::nonNull)
                         .filter(human -&gt; &quot;Robert&quot;.equals(human.getName())))

答案4

得分: 1

你只对 RoomList 执行了 .findFirst(),但你还需要对每个 Room 的内部列表即 EmployeeList 执行 .findFirst(),然后使用 .map()Room 转换为 Human,就像这样:

building.getRoomList()
    .stream()
    .map(room -> room.getEmployeeList()
                     .stream()
                     .filter(human -> human.getName().equals("Robert"))
                     .findFirst().get())
    .findFirst().get();

可以使用 flatMap 进行简化,先展平 EmployeeList,然后执行 findFirst

building.getRoomList()
        .flatMap(room -> room.getEmployeeList().stream())
        .filter(human -> human.getName().equals("Robert"))
        .findFirst().get();

注意:最好使用 .orElse() 而不是调用 .get()

英文:

You are doing .findFirst() on RoomList only but you need to do .findFirst() on inner list means EmployeeList of every Room also and transform Room into Human using .map(), like

building.getRoomList()
.stream()
.map(room -&gt; room.getEmployeeList()
                 .stream()
                 .filter(human -&gt; human.getName().equals(&quot;Robert&quot;))
                 .findFirst().get())
.findFirst().get();

Which can be simplified using flatMap to flatten then EmployeeList then get findFirst

building.getRoomList()
        .flatMap(e -&gt; room.getEmployeeList().stream())
        .filter(human -&gt; human.getName().equals(&quot;Robert&quot;))
        .findFirst().get();

Note: It's better to use .orElse() rather calling .get()

huangapple
  • 本文由 发表于 2020年10月2日 20:31:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/64171595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定