Java 8 stream partitioningBy second predicate on false 条件

Java 8 stream partitioningBy second predicate on false condition

最近我一直在我的代码中尽可能多地使用流,但是我 运行 遇到了一个我还没有完全解决的问题。

我有一个简单的 class 叫做 'Listing':

package models;

public class House {

private boolean isPrivate;
private Integer views;
private boolean hasSessionId;

public Listing(boolean isPrivate, Integer views, boolean hasSessionId) {
    this.isPrivate = isPrivate;
    this.views = views;
    this.hasSessionId = hasSessionId;
}

public boolean hasSessionId() {
    return hasSessionId;
}

public boolean isPublic() {
    return !isPrivate;
}

public boolean isPrivate() {
    return isPrivate;
}

public Integer getViews() {
    return views;
}

}

我有一个房屋列表,我想在其中制作一张地图,其中包含两个列表,这些列表的房屋通过特定条件隔离,我希望一个列表包含私人房屋,无论它们是否有会话 ID,另一个列表包含 public 个具有会话 ID 的房屋。

使用传统循环我可以实现我想要的功能,但我希望能够将其转换为使用流。

下面的测试 class 包含两个测试,第一个测试 shouldProduceTwoListsWithOneElementEach 使用传统的 for each 循环并遍历房屋列表并生成两个列表,一个包含 privateHouses,另一个包含 public houses or houses with a sessionId.

第二个测试 shouldSeperateWhetherHouseIsPrivate 是我最初尝试使用流,目前测试在第二个断言上失败,因为 partitioningBy 逻辑仅拆分房屋对象是否私有,因此 public 没有会话的房子最终被添加到另一个列表,通过 segregatedHouses.get(false).

访问
package models;

import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.junit.Before;
import org.junit.Test;

public class ListingsTest {

private List<House> houses;

@Before
public void setUp() {
    House publicListingWithSession = new House(false, 1, true);
    House privateListingWithoutSession = new House(true, 1, false);
    House publicListingWithNoViewsWithoutSession = new House(false, 0, false);

    this.houses = new ArrayList<House>();
    this.houses.add(publicListingWithSession);
    this.houses.add(privateListingWithoutSession);
    this.houses.add(publicListingWithNoViewsWithoutSession);
}

@Test
public void shouldProduceTwoListsWithOneElementEach() {
    List<House> privateHouses = new ArrayList<House>();
    List<House> publicHousesOrHasSessionId = new ArrayList<House>();

    for (House listing : houses) {
        if (listing.isPrivate()) {
            privateHouses.add(listing);
        } else if (listing.getViews() > 0 || listing.hasSessionId()) {
            publicHousesOrHasSessionId.add(listing);
        }
    }
    assertEquals(1, privateHouses.size());
    assertEquals(1, publicHousesOrHasSessionId.size());
}

@Test
public void shouldSeperateWhetherHouseIsPrivate() {
    Map<Boolean, List<House>> segregatedHouses = houses.stream()//
            .collect(Collectors.partitioningBy(p -> p.isPrivate()));

    assertEquals(1, segregatedHouses.get(true).size());
    assertEquals(1, segregatedHouses.get(false).size());
}

}

因此,如果谓词 p -> p.isPrivate() 的计算结果为真,则 House 对象将添加到 Map<Boolean, List<House>> segregatedHouses 中,可以通过 segregatedHouses.get(true) 访问该对象。如果谓词的计算结果为 false,那么 House 将被添加到另一个列表中,有没有办法在将 House 添加到将通过 segregatedHouses.get(false) 访问的列表之前再次评估 House?

非常感谢任何帮助!

我相信第二部分,您只需要私人房屋或 public 且 hasSessionId 分为 2 个列表的房屋。

试试这个...

Map<Boolean, List<House>> segregatedHouses = houses.stream()
        .filter(p -> p.isPrivate() || p.hasSessionId())
        .collect(Collectors.partitioningBy(p -> p.isPrivate()))