Java 8拆分器(或类似工具),在此处返回值';只有一个值

Java 8拆分器(或类似工具),在此处返回值';只有一个值,java,java-8,java-stream,spliterator,Java,Java 8,Java Stream,Spliterator,我非常喜欢singleOrEmptystream操作符。它不在std库中,但我发现它非常有用。如果一个流只有一个值,它将以可选的方式返回该值。如果它没有值或有多个值,则返回Optional.empty() 而不是按顺序结束 someList.stream().filter().map().singleOrEmpty() 这使得它比其他流机制更难读取 因此,作为这种流处理技术的新手,有没有人知道如何在一系列流转换的末尾设置一个短路singleOrEmpty机制?它不会像有限制(2)的机制那样快,

我非常喜欢
singleOrEmpty
stream操作符。它不在std库中,但我发现它非常有用。如果一个流只有一个值,它将以
可选的方式返回该值。如果它没有值或有多个值,则返回
Optional.empty()

而不是按顺序结束

someList.stream().filter().map().singleOrEmpty()
这使得它比其他流机制更难读取


因此,作为这种流处理技术的新手,有没有人知道如何在一系列流转换的末尾设置一个短路
singleOrEmpty
机制?

它不会像有限制(2)的机制那样快,但你可以将它用作
list.stream().filter(…).map(…).collect(singleOrEmpty())

静态收集器singleOrEmpty(){
返回收集器。正在收集,然后返回(
图(
可选::of,
收集器.reduceing((a,b)->可选.empty())
),
o->o.orElseGet(可选::空)
);
}
Stream.empty().collect(singleOrEmpty());//可选。空
Stream.of(1).collect(singleOrEmpty());//可选[1]
Stream.of(1,1).collect(singleOrEmpty());//可选。空
Stream.of(1,1).skip(1).collect(singleOrEmpty());//可选[1]
无论如何,除非这是真正的性能关键代码,否则我个人更喜欢不那么聪明但更清晰的实现

static<T> Collector<T,?,Optional<T>> singleOrEmpty() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            lst -> lst.size() == 1
                    ? Optional.of(lst.get(0))
                    : Optional.empty()
    );
}
静态收集器singleOrEmpty(){
返回收集器。正在收集,然后返回(
Collectors.toList(),
lst->lst.size()==1
?可选。of(第一次获取(0))
:可选。空()
);
}

第一个收集器可以通过重载版本的
收集器来简化。减少(…)
。我认为这个版本并不比你建议的第二个版本差(对不起,代码太多了,我觉得不值得单独回答)<代码>静态收集器singleOrEmptyCollector(){return Collector.reduction(Optional.empty(),Optional::of nullable,(opt,t)->opt.isPresent()^t.isPresent()?t:Optional.empty();}
另外,还有一件事需要提及。如果一个管道有一些昂贵的操作(比如
map((a)->doSomethingReallySlow(a))
),那么我们仍然必须在所有元素上执行它,即使我们只需要一个<代码>限制(2)可以拯救我们,但不是在所有情况下。有关详细信息,请参阅。因此,请小心,不要期望此收集器跳过除一个元素之外的所有元素(或者,至少像使用
stream.of(…).limit(2).collect(singleOrEmpty())
)。@StanislavLukyanov如果流有3个(或5、7等)元素,则收集器将失败。例如,
Stream.of(1,1,1).collect(…)
将返回可选的[1],而不是可选的.empty.谢谢!你说得对!实际上,我已经想出了更简单的技巧:
收集器。减少((a,b)->null)
。希望这次我没有错过任何东西:)
减少((a,b)->null)
有效!但感觉很不对
stream.reduce
如果reduce的结果为null,但Collectors.reduce不为空,则抛出NPE。我不知道这是故意的还是疏忽。使用此技巧的一个缺点是,由单个null组成的流将显示为空。也许一个更健壮的解决方案是
映射(Objects::requirennull,reduced((a,b)->null))
singleOrEmpty(someList.stream().filter(...).map(...))
someList.stream().filter().map().singleOrEmpty()
static <T> Collector<T, ?, Optional<T>> singleOrEmpty() {
    return Collectors.collectingAndThen(
            Collectors.mapping(
                    Optional::of,
                    Collectors.reducing((a, b) -> Optional.empty())
            ),
            o -> o.orElseGet(Optional::empty)
    );
}

Stream.empty().collect(singleOrEmpty());   // Optional.empty
Stream.of(1).collect(singleOrEmpty());     // Optional[1]
Stream.of(1, 1).collect(singleOrEmpty());  // Optional.empty
Stream.of(1, 1).skip(1).collect(singleOrEmpty());  // Optional[1]
static<T> Collector<T,?,Optional<T>> singleOrEmpty() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            lst -> lst.size() == 1
                    ? Optional.of(lst.get(0))
                    : Optional.empty()
    );
}