【问题标题】:Java: Get first item from a collectionJava:从集合中获取第一个项目
【发布时间】:2010-12-12 21:13:56
【问题描述】:

如果我有一个集合,例如Collection<String> strs,我如何才能取出第一个项目?我可以打电话给Iterator,拿走它的第一个next(),然后把Iterator扔掉。有没有更浪费的方法?

【问题讨论】:

标签: java collections iterable


【解决方案1】:

我用过这个:

strs.isEmpty() ? "" : strs.iterator().next();

?

【讨论】:

    【解决方案2】:

    功能方式:

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

    上面的代码 sn-p 保留 NullPointerException 和 IndexOutOfBoundsException

    【讨论】:

    • 您对List&lt;T&gt; 的选择不满足它应该适用于Collection&lt;String&gt; 的条件,但当然可以使用Collection&lt;T&gt; 来解决这个问题,并进行额外的更改:.map(Collection::stream) .
    【解决方案3】:

    看起来这是最好的方法:

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

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

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

    虽然看起来有点浪费,但它可能没有你想象的那么糟糕。 Iterator 实际上只包含集合中的索引信息,而不是通常整个集合的副本。调用此方法确实会实例化 Iterator 对象,但这确实是唯一的开销(不像复制所有元素)。

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

    请务必检查iterator() 的返回,因为它可能为空或null,具体取决于实现。

    【讨论】:

    • 重要的是要注意这个“技巧”只有在集合实际有内容时才有效。如果它是空的,迭代器可能会返回一个错误,其中必须事先检查集合大小。
    • 这应该是正确的答案。我不明白为什么答案总是“使用另一个库!” .
    • 集合的第二个元素怎么样?为什么 first->next() 不起作用?我该怎么办?谢谢!
    • 不够安全,不能保证集合总是指向第一个元素。
    • 这应该是公认的答案:简单且没有额外要求。
    【解决方案4】:

    Guava 提供了一个onlyElementCollector,但仅当您希望集合只有一个元素时才使用它。

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

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

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

    【讨论】:

      【解决方案5】:

      在 Java 8 中:

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

      对于老版本的java,Guava中有一个getFirst方法Iterables

      Iterables.getFirst(iterable, defaultValue)
      

      【讨论】:

      • java 8 解决方案特别有用,因为它可以优雅地处理集合为空的情况。
      • 不好。你添加了 stream() 的开销来获得一个 get(0) 只是因为你懒得写 4 行代码。 if(!CollectionUtils.isEmpty(productList)){ return Optional.of(productList.get(0)); } return Optional.empty();
      • 我没有可用的getFirst 方法。有getgetLast 方法
      • @R.S 如果你不能调用 productList.get(0) 会发生什么,因为它是一个集合..? (根据 OP 问题)
      【解决方案6】:

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

      Collection<String> getStrings();
      

      调用它之后,你需要第一个元素,你可以这样做:

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

      【讨论】:

        【解决方案7】:

        在 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);
        }
        

        【讨论】:

        【解决方案8】:

        Iterables.get(yourC, indexYouWant)

        因为真的,如果您使用收藏,那么您应该使用 Google 收藏。

        【讨论】:

        • 它做同样的事情,它只是首先检查它是否是一个列表,如果是则通过索引获取。它还有一些代码可以尝试在实际的 Collection 上更快地失败(也就是说,如果索引太大,它会尝试在不遍历整个事物并在最后抛出异常的情况下找出它)。
        • 老实说,就性能而言,它可能比 c.iterator().next() 稍慢 - 但代码更清晰,更易于修改。
        • 我当然同意它更干净,但是 OP 是浪费,但我想既然你的回答被接受了,那就是所希望的。
        • 对于那些(仍然)到达这里的人:我认为 jheddings 的答案可能是最好的“完成它”的答案,尽管对于我' m 已经在使用 GC 库。我的答案实际上是针对以后可能想要灵活编写的情况(例如,如果一个人决定 second 元素是新的热点)。
        • 有时你只是在使用使用集合的代码,所以没什么可做的。
        【解决方案9】:

        这完全取决于你使用了哪种实现,是arraylistlinkedlist,还是set的其他实现。

        如果设置了,那么你可以直接获取第一个元素,它们可以在集合上进行技巧循环,创建一个值为 1 的变量,并在标志值为 1 时获取值,然后打破该循环。

        如果是列表的实现,那么定义索引号就很容易了。

        【讨论】:

          【解决方案10】:

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

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

          【讨论】:

            【解决方案11】:

            Collection 中没有“第一个”项目这样的东西,因为它只是一个集合。

            来自 Java 文档的 Collection.iterator() 方法:

            不保证返回元素的顺序...

            所以你不能。

            如果您使用另一个界面,例如List,您可以执行以下操作:

            String first = strs.get(0);
            

            但直接从集合中这是不可能的。

            【讨论】:

            • 我不认为get(int n) 是为Collection 定义的
            • 你说得对,我错过了这一点。我已经更新了答案。你不能! (除非 Collection 是由一些允许提供保证的底层类实现的)
            • get不在Collection界面
            • 奥斯卡,我认为你夸大了情况。在 HashSet 等少数情况下,Collection 的第一个元素可能是任意的,但它是明确定义的:它是 .iterator().next()。在我见过的每个集合实现中,它也是稳定的。 (相关:请注意,虽然 Set 不保证顺序,但 JDK 中除 HashSet 之外的每个 Set 子类型都可以。)
            • 可能是这样,但是考虑一下当你向集合中添加一个新元素时,你不知道(通过接口)该元素是第一个,最后一个,还是它会是插在中间。为了获得精确的结果,您应该使用另一个界面。然而,无论如何,Rosarch 可能需要的是第一个元素。了解底层集合可能会有所帮助,但它会阻止您更改它。
            【解决方案12】:

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

            您可以使用多种结构来获取订单,但您需要对其进行强制转换。

            【讨论】:

            • 我同意,如果您不想迭代,请不要使用集合。改用其他更具体的界面。
            • 我想知道......假设实际的底层数据是一个 SortedSet,所以顺序是有意义的,但你只有一个 Collection 视图(假设是一个非愚蠢的原因);如果您将集合转换为列表、队列等并尝试获取/轮询/等,是否会发生灾难?同样,如果底层结构是 List,依此类推。
            • @Cal - 我没有尝试过,但是如果你将一个集合转换为与原来完全不同的类型,你应该会得到一个错误,但是,我没有尝试过,所以我可能是错的。
            【解决方案13】:

            你可以这样做:

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

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

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

            【讨论】:

            • 这会创建一个新的 String 数组,比创建一个迭代器要昂贵得多。
            • 是的,我在发布此内容后想到了这一点。无论使用哪种方法,排序都取决于 Collection 的底层实现。 “首先”然后成为一个相对术语。但是,在大多数情况下,iterator() 的执行方式可能会更好。
            • 我来到这里是因为这是我所拥有的解决方案,但我发现它很丑。
            猜你喜欢
            • 1970-01-01
            • 2015-11-01
            • 2011-01-19
            • 2016-05-16
            • 2022-01-02
            • 2013-02-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多