Java:从集合中获取第一项


277

如果我有一个收藏,例如Collection<String> strs,我如何拿出第一件?我可以先叫一个Iterator,先取一个next(),然后扔掉Iterator。有没有更浪费的方法呢?


1
当然,如果您知道实现容器的类,可能会有更好的方法来访问第一个元素……
Rooke


1
听起来您需要Queue.peek()
约翰内斯

Answers:


131

Iterables.get(yourC,indexYouWant)

因为实际上,如果您使用的是收藏夹,则应该使用Google收藏夹。


7
那做同样的事情,它只是首先检查它是否是一个列表,如果是则按索引获取。它还有一些代码可以尝试在实际的Collection上更快地失败(也就是说,如果索引太大,它会试图找出原因,而不会遍历整个事物并在最后抛出异常)。
Yishai

1
老实说,就性能而言,它可能比c.iterator()。next()稍慢-但代码更清晰,更易于修改。
卡尔,

2
我当然同意它更干净,但是操作是浪费的,但是我想既然您的答案被接受了,那是所期望的。
Yishai

8
对于那些仍然到达这里的人:我认为jheddings的答案可能是最好的“完成”答案,尽管在我已经在使用GC库的情况下,我更喜欢@DonaldRaab的答案(在页面的下方)。我的答案确实是针对这样的情况,即以后可能要灵活地编写(例如,如果确定第二个要素是新的热点)。
卡尔,

4
有时您只是在使用使用Collections的代码,因此没有太多要做。
erickrf

436

看起来这是最好的方法:

String first = strs.iterator().next();

很好的问题...起初,它似乎是对Collection接口的疏忽。

请注意,“ first”并不总是返回您放入集合中的第一件事,并且仅对有序集合有意义。也许这就是为什么没有get(item)电话的原因,因为不一定要保留订单。

尽管这似乎有些浪费,但它可能没有您想像的那么糟糕。该Iterator真的只是包含索引信息到集合,而不是通常的整个集合的副本。调用此方法确实会实例化该Iterator对象,但这实际上是唯一的开销(与复制所有元素不同)。

例如,查看ArrayList<String>.iterator()方法返回的类型,我们看到它是ArrayList::Itr。这是一个内部类,仅直接访问列表的元素,而不是复制它们。

只需确保您检查的返回值即可,iterator()因为它可能为空或null取决于实现。


3
重要的是要注意,此“技巧”仅在集合实际具有内容时才起作用。如果为空,则迭代器可能会返回错误,其中必须事先检查集合大小。
spaceemotion 2015年

20
这应该是正确的答案。我不明白为什么答案总是“使用另一个库”!。
库泽科

集合的第二个元素怎么样?为什么first-> next()不起作用?我该怎么办?谢谢!
pb772

不够安全,因此不能保证集合将始终指向第一个元素。

84

在Java 8中:

Optional<String> firstElement = collection.stream().findFirst();

对于较旧的Java版本,Guava Iterables中有一个getFirst方法:

Iterables.getFirst(iterable, defaultValue)

6
Java 8解决方案特别有用,因为它可以很好地处理集合为空的情况。
SpaceTrucker '16

4
不好。您添加stream()的开销以获得get(0)只是因为您懒于编写4行代码。if(!CollectionUtils.isEmpty(productList)){返回Optional.of(productList.get(0)); } return Optional.empty();
RS

我没有getFirst可用的方法。有getgetLast方法
user1209216

4
@RS,如果您不能调用productList.get(0),因为它是Collection,会发生什么情况?(根据OP问题)
Denham Coote

40

在其中没有“第一”项目,Collection因为它只是一个集合。

通过Java文档的Collection.iterator()方法:

无法保证元素返回的顺序...

所以你不能。

如果您使用另一个接口(例如List),则可以执行以下操作:

String first = strs.get(0);

但是不可能直接从Collection中进行。


11
我认为这不是get(int n)针对Collection
Nick Heiner的2009年

2
您说得对,我想念这一点。我已经更新了答案。你不能!(除非Collection是由允许提供保证的某些底层类实现的)
OscarRyz

获取不在收藏

21
奥斯卡,我认为您对此事夸大了。在某些情况下,像HashSet这样,Collection的第一个元素可能是任意的,但它定义明确:它是.iterator()。next()。在我见过的每个collection实现中,它也是稳定的。(相关:请注意,尽管Set不能保证顺序,但JDK中除HashSet之外的Set的每个子类型都可以。)
Kevin Bourrillion 09年

3
可能是这样,但是考虑到在集合中添加新元素的情况,您(通过界面)不知道该元素是第一个,最后一个,还是将其插入中间。为了获得准确的结果,您应该使用另一个界面。然而,不管怎样,罗萨克可能需要的是第一要素。知道底层收集可能会有所帮助,但会阻止您进行更改。
OscarRyz

4

听起来您的收藏集想要像列表一样,所以我建议:

List<String> myList = new ArrayList<String>();
...
String first = myList.get(0);

2

在Java 8中,您需要使用许多运算符,例如limit

     /**
 * Operator that limit the total number of items emitted through the pipeline
 * Shall print
 * [1]
 * @throws InterruptedException
 */
@Test
public void limitStream() throws InterruptedException {
    List<Integer> list = Arrays.asList(1, 2, 3, 1, 4, 2, 3)
                               .stream()
                               .limit(1)
                               .collect(toList());
    System.out.println(list);
}

2
@Vitalii Fedorenko的答案stackoverflow.com/a/18165855/1562662更好。
Chacko Mathew'3

2

Guava提供了onlyElement Collector,但只有在您希望集合中只有一个元素时才使用它。

Collection<String> stringCollection = ...;
String string = collection.stream().collect(MoreCollectors.onlyElement())

如果不确定有多少个元素,请使用findFirst

Optional<String> optionalString = collection.stream().findFirst();

1

您可以进行转换。例如,如果存在一个具有此定义的方法,并且您知道该方法正在返回List:

Collection<String> getStrings();

在调用它之后,您需要第一个元素,您可以像这样进行操作:

List<String> listString = (List) getStrings();
String firstElement = (listString.isEmpty() ? null : listString.get(0));

0

如果您知道集合是一个队列,则可以将集合强制转换为队列并轻松获取。

您可以使用几种结构来获取订单,但是您需要将其强制转换为订单。


我同意,如果您不想迭代,请不要使用collection。请改用其他一些更具体的界面。
Adeel Ansari

1
我不知道...虽然说实际的基础数据是SortedSet,所以顺序是有意义的,但是您只有它的Collection视图(出于非愚蠢的原因,我们可以说)。如果将集合强制转换为列表,队列等并尝试获取/轮询/等,是否会发生灾难?同样,如果基础结构是List,依此类推。
卡尔,

@Cal-我没有尝试过,但是如果将集合转换为与原始类型完全不同的类型,则会出现错误,但是我没有尝试过,所以我可能是错误的。
James Black

0

这完全取决于您使用的是哪种实现,无论是arraylist链表还是set的其他实现。

如果已设置,则可以直接获取第一个元素,可以在集合上进行特技循环,创建值1的变量,并在中断该循环后在flag值为1时获取值。

如果是列表的实现,则通过定义索引号很容易。


0

功能方式:

public static <T> Optional<T> findFirst(List<T> result) {
    return Optional.ofNullable(result)
            .map(List::stream)
            .flatMap(Stream::findFirst);
}

上面的代码段保留为NullPointerException和IndexOutOfBoundsException


1
您对的选择List<T>不满足它适用于的条件Collection<String>,但当然可以使用进行固定,但需要进行Collection<T>额外的更改:.map(Collection::stream)
刮擦

-2

您可以这样做:

String strz[] = strs.toArray(String[strs.size()]);
String theFirstOne = strz[0];

Collection的javadoc对数组元素给出以下警告:

如果此集合保证其迭代器返回其元素的顺序,则此方法必须以相同的顺序返回元素。


2
这将创建一个新的String数组,比创建迭代器要昂贵得多。
Jim Ferrans 09年

是的,我在发布此内容后就想到了这一点。无论使用哪种方法,排序都取决于Collection的基础实现。然后,“第一”成为相对术语。但是,在大多数情况下,使用iterator()方法可能会更好。
2009年

2
我来这里是因为这是我曾经发现的丑陋的解决方案。
haan​​sn08 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.