有没有一种惯用的方法来断言流只有一个元素而产生该元素? [复制]
Posted
技术标签:
【中文标题】有没有一种惯用的方法来断言流只有一个元素而产生该元素? [复制]【英文标题】:Is there an idiomatic way to assert a stream has only one element while yielding that element? [duplicate] 【发布时间】:2021-07-19 05:24:17 【问题描述】:从这段代码开始:
public Thing thereCanBeOnlyOne(Stream<Thing> stream)
List<Thing> things = stream.collect(Collectors.toList());
if(things.size() != 1)
throw new IllegalArgumentException();
return things.get(0);
有没有更简洁的方式来表达方法体?
到目前为止我尝试了什么:
我阅读了Collector
和reduce
的文档,但没有找到任何东西。
【问题讨论】:
.reduce(IDENTITY, (a, b) -> if(a.equals(IDENTITY)) return b; throw new IllegalArgumentException(); );
但这取决于你的口味。
取决于您的“惯用语”阈值:Guava 的 Iterables.getOnlyElement
将是我的首选。
哦,番石榴也有MoreCollectors.onlyElement
收集器。
@AndyTurner 肯定为此目的的外部库是矫枉过正?
@OleV.V.这不完全是一个正在工作的外部库;)当然,如果这就是你所需要的,那就太过分了。但是,如果您已经在使用它,那就太好了。存在其他库,ofc,因此您可以在您已经使用的库中找到等效的库。
【参考方案1】:
如果您喜欢使用 Guava,请使用 MoreCollectors.onlyElement
:
public Thing thereCanBeOnlyOne(Stream<Thing> stream)
return stream.collect(MoreCollectors.onlyElement());
等价物很可能存在于其他常用库中;我只是熟悉番石榴。
【讨论】:
这很好。我还发现.collect(Collectors.reducing((a, b) -> null));
是一个有趣的替代方案(返回 null 而不是抛出异常)。【参考方案2】:
怎么样
public static Thing thereCanBeOnlyOne(Stream<Thing> stream)
Object[] array = null;
if((array = stream.limit(2).toArray()).length != 1)
throw new IllegalArgumentException();
return (Thing)array[0];
在我看来,开销似乎更少。
【讨论】:
stream.limit(2).toArray()
在流中“很多”的情况下会更好。此外,null 赋值是多余的,只需在声明时从流中分配数组即可。
不确定这里提到了哪些开销,但stream.limit(2).toArray(Thing[]::new)
可能会为您提供准确的类型
我计算了调用收集器和创建列表的开销。如果我不先声明数组,由于范围问题,将找不到返回第一个元素。是的,我本可以只处理流然后检查长度,但我没有。我喜欢limit
的想法希望我能想到它:)
也可以使用public static <T> T thereCanBeOnlyOne(Stream<T> stream)
和@SuppressedWarnings("unchecked")
使其更加通用。在这种情况下投射 Object to T
应该不会导致问题。
这不再简洁明了。问题实际上与开销无关,但既然您提到它,当流在运行时预计仅包含 1 个元素时,开销是相同的。以上是关于有没有一种惯用的方法来断言流只有一个元素而产生该元素? [复制]的主要内容,如果未能解决你的问题,请参考以下文章