84

给定一个简单Set<T>,从?Set

使用List,很容易:

List<T> things = ...;
return things.get(0);

但是,对于 a Set,没有.get(...)方法,因为Sets 没有排序。

4

3 回答 3

117

ASet<T>是 a Iterable<T>,因此迭代到第一个元素有效:

Set<T> things = ...;
return things.iterator().next();

Guava 有一种方法可以做到这一点,尽管上面的代码片段可能更好

于 2012-12-03T22:13:00.753 回答
17

由于存在流,因此您也可以这样做,但是您必须使用 class java.util.OptionalOptional是元素的包装类或明确的无元素(避免 Nullpointer)。

//returns an Optional.
Optional <T> optT = set.stream().findAny();

//Optional.isPresent() yields false, if set was empty, avoiding NullpointerException
if(optT.isPresent()){
    //Optional.get() returns the actual element
    return optT.get();
}

编辑:正如我Optional自己经常使用的那样:有一种方法可以访问元素或获取默认值,以防它不存在:
optT.orElse(other)返回元素或者,如果不存在,则返回other. other可能是null,顺便说一句。

于 2018-05-23T11:52:21.527 回答
4

从 Set 或 Collection 中获取任何元素似乎是一种不常见的需求——如果不是任意的或不拘一格的——但是,例如,当需要计算Map 中 Keys 或 Values 对象的统计信息并且必须初始化 min/时,这是很常见的。最大值在更新每个元素的最小/最大值之前,集合/集合中的任何元素(由 Map.keySet() 或 Map.values() 返回)将用于此初始化。

那么,当面对这个问题并同时试图保持较小的内存和执行时间以及代码清晰时,有什么选择呢?

通常你会得到通常的:“将 Set 转换为 ArrayList 并获取第一个元素”。伟大的!另一个包含数百万个项目的数组和额外的处理周期,用于从 Set中检索对象、分配数组并填充它:

HashMap<K,V> map;
List<K> list = new ArrayList<V>(map.keySet()); // min/max of keys
min = max = list.get(0).some_property(); // initialisation step
for(i=list.size();i-->1;){
 if( min > list.get(i).some_property() ){ ... }
 ...
}

或者可以使用带有迭代器的循环,使用标志来表示需要初始化最小值/最大值,并使用条件语句检查是否为循环中的所有迭代设置了该标志。这意味着大量的条件检查。

boolean flag = true;
Iterator it = map.keySet().iterator();
while( it.hasNext() ){
  if( flag ){
    // initialisation step
    min = max = it.next().some_property();
    flag = false;
  } else {
    if( min > list.get(i).some_property() ){ min = list.get(i).some_property() }
  ...
  }
}

或者在循环外进行初始化:

HashMap<K,V> map;
Iterator it = map.keySet().iterator();
K akey;
if( it.hasNext() ){
  // initialisation step:
  akey = it.next();
  min = max = akey.value();
  do {
    if( min > list.get(i).some_property() ){ min = akey.some_property() }
  } while( it.hasNext() && ((akey=it.next())!=null) );
}

但是,当需要 min/max 时,是否真的值得代表程序员(并代表 JVM 设置迭代器)进行所有这些操作?

来自 javally-correct ol' 运动的建议很可能是:“将您的 Map 包装在一个类中,该类在放置或删除时跟踪最小值和最大值!”。

还有另一种情况,根据我的经验,需要地图中的任何项目。这就是地图包含具有共同属性的对象(该地图中的所有对象都相同)并且您需要读取该属性的情况。例如,假设有一个具有相同直方图的存储箱的地图,这些箱具有相同的维数。给定这样的 Map,您可能需要知道Map 中任意Histobin 的维数,以便创建另一个相同维数的 Histobin。我是否需要再次设置一个迭代器并在调用 next() 一次后处理它?对于这种情况,我将跳过 javally 正确的人的建议。

如果获取any元素的所有麻烦导致显着的内存和 cpu 周期增加,那么为了获取难以获取的任何元素而必须编写的所有代码呢?

我们需要any元素。给我们吧!

于 2017-03-29T14:56:50.390 回答