[英]The correct way to return the only element from a set
我有以下情况:
Set<Element> set = getSetFromSomewhere();
if (set.size() == 1) {
// return the only element
} else {
throw new Exception("Something is not right..");
}
假设我无法更改getSetFromSomewhere()
的返回类型,是否有比返回集合中唯一元素更好或更正确的方法
.get(0)
您可以使用Iterator
来获取唯一元素以及验证集合是否仅包含一个元素(从而避免size()
调用和不必要的列表创建):
Iterator<Element> iterator = set.iterator();
if (!iterator.hasNext()) {
throw new RuntimeException("Collection is empty");
}
Element element = iterator.next();
if (iterator.hasNext()) {
throw new RuntimeException("Collection contains more than one item");
}
return element;
您通常会将其包装在自己的方法中:
public static <E> E getOnlyElement(Iterable<E> iterable) {
Iterator<E> iterator = iterable.iterator();
// The code I mentioned above...
}
请注意,此实现已经是 Google 的Guava 库的一部分(我强烈推荐,即使您不将它用于此特定代码)。 更具体地说,该方法属于Iterables
类:
Element element = Iterables.getOnlyElement(set);
如果你对它是如何实现的感到好奇,你可以查看Iterators
类源代码( Iterables
中的Iterables
经常调用Iterators
方法):
/**
* Returns the single element contained in {@code iterator}.
*
* @throws NoSuchElementException if the iterator is empty
* @throws IllegalArgumentException if the iterator contains multiple
* elements. The state of the iterator is unspecified.
*/
public static <T> T getOnlyElement(Iterator<T> iterator) {
T first = iterator.next();
if (!iterator.hasNext()) {
return first;
}
StringBuilder sb = new StringBuilder();
sb.append("expected one element but was: <" + first);
for (int i = 0; i < 4 && iterator.hasNext(); i++) {
sb.append(", " + iterator.next());
}
if (iterator.hasNext()) {
sb.append(", ...");
}
sb.append('>');
throw new IllegalArgumentException(sb.toString());
}
最好的通用解决方案(您不知道实际的集合类)是:
Element first = set.iterator().next();
如果已知集合类是SortedSet
(例如TreeSet
或ConcurrentSkipListSet
),那么更好的解决方案是:
Element first = ((SortedSet) set).first();
在这两种情况下,如果集合为空都会抛出异常; 检查javadocs。 使用Collection.isEmpty()
可以避免异常。
第一个解决方案是HashSet
或LinkedHashSet
时间和空间O(1)
,但对于其他类型的集合通常更糟。
第二个是O(logN)
时间,并且不为TreeSet
或ConcurrentSkipListSet
使用空间。
从集合内容创建列表然后调用List.get(0)
给出了一个糟糕的解决方案,因为第一步是时间和空间上的O(N)
操作。
我没有注意到N
实际上是1
。 但即便如此,创建迭代器可能比创建临时列表更便宜。
你可以抓住迭代器:
Element firstEl = set.iterator().next();
在 Java 8 中,我们可以这样做:
set.stream().findFirst().get()
但是,记得在Optional.get()
抛出NoSuchElementException
之前检查 set 的大小
我有以下几种情况:
Set<Element> set = getSetFromSomewhere();
if (set.size() == 1) {
// return the only element
} else {
throw new Exception("Something is not right..");
}
假设我无法更改getSetFromSomewhere()
的返回类型,是否有比该方法更好或更正确的方法来返回集合中的唯一元素?
.get(0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.