Java8过滤并仅返回元素

时间:2018-03-13 10:02:27

标签: java filter java-8 java-stream

如何使用java8流过滤列表并返回找到的元素(如果它是过滤列表中的唯一元素),否则(如果有更多满足条件,或者没有满足条件的结果)返回例如Optional.empty()

我需要这样的东西:

假设我有:

List<String> list = Arrays.asList("Apple","Banana","Peach");

然后我想:

Optional<String> string = list.stream()
    .filter(item -> item.startsWith("A"))
    .findOne();

我知道我可以通过以下方式实现:

boolean singleElement = list.stream()
        .filter(item -> item.startsWith("A"))
        .count() == 1;

String string = null;

if(singleElement){
  string = list.stream().filter(item -> item.startsWith("A")).iterator().next();
}

但是我想知道我是否可以在一个流中完成它?

是否有任何单一流解决方案?

3 个答案:

答案 0 :(得分:6)

不是很漂亮,但您可以limitcollect流转换为List中的2个元素,List<String> tmp = list.stream() .filter(item -> item.startsWith("A")) .limit(2) .collect(Collectors.toList()); Optional<String> res = tmp.size() == 1 ? Optional.of(tmp.get(0)) : Optional.empty(); ,并查看该列表是否只包含一个元素。这仍然有多行,并且有一些开销用于创建列表,但开销有限(到大小为2的列表),并且它也不必迭代流两次。

reduce((s1, s2) -> null)

(我的另一个想法是在limit(2)之后使用null并将任意两个匹配减少到Optional.empty,但不会返回reduce这只会引发异常,即它工作,但也许这会触发更好的(工作)想法。)

更新:似乎在Collectors.reducing提出异常时,Optional.empty没有,而是根据需要返回limit(2),所以这也有效,如{{3}所示一个非常相似的问题。不过,我会添加Optional<String> res = list.stream() .filter(item -> item.startsWith("A")) .limit(2) .collect(Collectors.reducing((s1, s2) -> null)); 以提前停止:

            <View style={styles.viewPointOverview}>
                <Text > Point overview: </Text>
                <FlatList
                    ref={(ref) => this.flatList = ref}
                    data={pointRecord}
                    renderItem={({ item }) => <Text>{item}</Text>}
                />
            </View>

(如果您喜欢这最后一部分,请提交原始答案。)

答案 1 :(得分:2)

我不知道这对您来说是否算作单一操作,但您可以这样做:

Arrays.asList("Apple", "Banana", "Peach")
            .stream()
            .collect(Collectors.collectingAndThen(
                    Collectors.partitioningBy(
                            x -> x.startsWith("A")),
                    map -> {
                        List<String> list = map.get(Boolean.TRUE);
                        return list.size() == 1 ? Optional.of(list.get(0)) : Optional.empty();
                    }));

答案 2 :(得分:2)

您可以使用Google GuavaMoreCollectors.onlyElement,如下所示:

    List<String> list = Arrays.asList("Apple", "Banana", "Peach");
    String string = null;
    try {
        string = list.stream()
                .filter(item -> item.startsWith("A"))
                .collect(MoreCollectors.onlyElement());
    } catch (NoSuchElementException | IllegalArgumentException iae) {
        System.out.println("zero or more than one elements found.");
    }
    Optional<String> res = string == null ? Optional.empty() : Optional.of(string);

请注意,如果没有元素,则会抛出NoSuchElementException,如果有多个元素,则会抛出IllegalArgumentException