如果集合中只存在一个元素,我最近需要做'特殊情况'场景。检查...size() == 1
并使用...iterator.next()
检索看起来很难看,所以我在home brew Collections类中创建了两种方法:
public class Collections {
public static <T> boolean isSingleValue(Collection<T> values) {
return values.size() == 1;
}
public static <T> T singleValue(Collection<T> values) {
Assert.isTrue(isSingleValue(values));
return values.iterator().next();
}
}
前几天我发现Guava有一种名为Iterables.getOnlyElement的方法。它涵盖了我的需求并替换了singleValue
,但找不到isSingleValue
的匹配项。这是设计的吗?是否值得为Iterables.isOnlyElement
方法提出功能请求?
修改 由于赞成很少,我决定在番石榴上开放增强 - issue 957。最终决议 - 'WontFix'。争论与Thomas / Xaerxess提供的非常相似。
答案 0 :(得分:10)
嗯,用一个方法替换values.size() == 1
你不会获得太多收益,除非你可以检查null。但是,Apache Commons Collections(以及我假设的Guava)中有一些方法可以做到这一点。
我宁愿写if( values.size() == 1 )
或if( SomeHelper.size(values) == 1 )
而不是if( SomeHelper.isSingleValue(values) )
- 前两种方法的意图更清晰,而且编写的代码与第三种方法。
答案 1 :(得分:6)
除了其他答案之外(我打算写一些类似@daveb的人删除他的那个:如果没有一个元素,那么Iterables#getOnlyElement
会抛出一个IllegalArgumentException
或者NoSuchElementException
) - 回答问题,为什么番石榴中没有Iterables.isSingleValue(Iterable)
。
我认为你犯了这个错误。如果:
next()
不同,这就是hasNext()
存在的原因)null
返回的Map#get(Object)
不同 - 它可以是空值,也可能意味着在地图中找不到该键)如果条件为真,则不需要方法检查,然后在示例代码中执行某些操作(使用断言!)。
如果你完全确定这个地方的迭代不能有1以外的大小,那么条件检查是多余的(在其他情况下抛出异常)。
如果你只想获得非空集合中的第一个元素 - collection.iterator.next()
完全没问题(如果集合为空则抛出NoSuchElementException
。)
如果您对集合的大小一无所知,那么Iterables.getFirst(iterable, default)
就是适合您。
P.S。如果您的Collections#isSingleValue
仅在本地使用(因此可能是私有的)真的意味着您在调用Iterables#getOnlyValue
之前不需要该检查。
P.P.S。关于Guava设计的问题的另一个答案可能是Joshua Bloch的 Effective Java 的第57项 - 我之前提到过的Guava中几乎没有不同的辅助方法明确说明每个方法的例外情况;因为保持API尽可能小,所以没有添加布尔检查。
答案 2 :(得分:0)
现在我遇到了同样的问题。
我将用这段代码解决:
public static <T> void hasJustOne(T... values) {
hasJustOne(Predicates.notNull(), values);
}
public static <T> void hasJustOne(Predicate<T> predicate, T... values) {
Collection<T> filtred = Collections2.filter(Arrays.asList(values),predicate);
Preconditions.checkArgument(filtred.size() == 1);
}