for-each 与 for 与 while

发布于 2024-10-06 05:39:36 字数 514 浏览 0 评论 0原文

我想知道在 ArrayList 或每种列表上实现“for-each”循环的最佳方法是什么。

以下哪种实现最好,为什么?或者有没有最好的办法?

感谢您的帮助。


List values = new ArrayList();

值.add(“一”); 值.add(“两个”); 值.add(“三”); ...

//#0
for(字符串值:值){ ... }

//#1
for(int i = 0; i

//#2
for(迭代器 it = value.iterator(); it.hasNext(); ) { 字符串值 = it.next(); ... }

//#3
迭代器 it = value.iterator(); while (it.hasNext()) { 字符串值 = (String) it.next(); ... }

I wonder what is the best way to implement a "for-each" loop over an ArrayList or every kind of List.

Which of the followings implementations is the best and why? Or is there a best way?

Thank you for your help.


List values = new ArrayList();

values.add("one"); values.add("two"); values.add("three"); ...

//#0
for(String value : values) { ... }

//#1
for(int i = 0; i < values.size(); i++) { String value = values.get(i); ... }

//#2
for(Iterator it = values.iterator(); it.hasNext(); ) { String value = it.next(); ... }

//#3
Iterator it = values.iterator(); while (it.hasNext()) { String value = (String) it.next(); ... }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

走野 2024-10-13 05:39:36

#3 有一个缺点,因为迭代器 it 的范围超出了循环末尾。其他解决方案不存在此问题。

#2 与 #0 完全相同,只是 #0 更具可读性且不易出错。

#1(可能)效率较低,因为它每次循环都会调用 .size()

#0 通常是最好的,因为:

  • 它是最短的
  • 它最不容易出错
  • 它是惯用的并且易于其他人一目了然地阅读
  • 它是由编译器有效实现的
  • 它不会污染您的方法范围(循环之外)不必要的名字

#3 has a disadvantage because the scope of the iterator it extends beyond the end of the loop. The other solutions don't have this problem.

#2 is exactly the same as #0, except #0 is more readable and less prone to error.

#1 is (probably) less efficient because it calls .size() every time through the loop.

#0 is usually best because:

  • it is the shortest
  • it is least prone to error
  • it is idiomatic and easy for other people to read at a glance
  • it is efficiently implemented by the compiler
  • it does not pollute your method scope (outside the loop) with unnecessary names
感情旳空白 2024-10-13 05:39:36

简短的答案是使用版本 0。查看 Android 性能设计文档。该页面有很多好东西,并且非常清晰简洁。

The short answer is to use version 0. Take a peek at the section title Use Enhanced For Loop Syntax at Android's documentation for Designing for Performance. That page has a bunch of goodies and is very clear and concise.

忆伤 2024-10-13 05:39:36

在我看来,#0 是最容易阅读的,但#2 和#3 也同样有效。这三者之间应该没有性能差异。

几乎在任何情况下都不应该使用#1。您在问题中指出您可能想要迭代“每种列表”。如果您碰巧在 LinkedList 上进行迭代,那么 #1 将是 n^2 复杂度:不好。即使您绝对确定您使用的列表支持高效的随机访问(例如ArrayList),通常也没有理由使用#1 而不是其他任何列表。

#0 is the easiest to read, in my opinion, but #2 and #3 will work just as well. There should be no performance difference between those three.

In almost no circumstances should you use #1. You state in your question that you might want to iterate over "every kind of List". If you happen to be iterating over a LinkedList then #1 will be n^2 complexity: not good. Even if you are absolutely sure that you are using a list that supports efficient random access (e.g. ArrayList) there's usually no reason to use #1 over any of the others.

蓝天白云 2024-10-13 05:39:36

针对OP的这一评论。

但是,更新时需要#1(如果不仅仅是改变当前项目或将结果构建为新列表)并且附带索引。由于列表<>是一个 ArrayList<>在本例中,get()(和 size())的时间复杂度为 O(1),但这对于所有列表合约类型来说并不相同。

让我们看看这些问题:

对于 List 合约的所有实现来说,get(int) 确实不是 O(1)。但是,据我所知,对于 java.util 中的所有 List 实现,size() 都是 O(1)。但你是对的,#1 对于许多 List 实现来说并不是最优的。事实上,对于像 LinkedList 这样的列表,其中 get(int)O(N),#1 方法会导致 O( N^2) 列表迭代。

在 ArrayList 情况下,手动提升对 size() 的调用并将其分配给(最终)局部变量是一件简单的事情。通过这种优化,对于 ArrayList,#1 代码比其他情况要快得多。

您关于在迭代元素时更改列表的观点引发了许多问题:

  • 如果您使用显式或隐式使用迭代器的解决方案执行此操作,则根据列表类,您可能会得到ConcurrentModificationException s。如果您使用并发集合类之一,则不会出现异常,但 javadoc 声明迭代器不一定会返回所有列表元素。

  • 如果您使用#1 代码(按原样)执行此操作,则会遇到问题。如果修改是由同一个线程执行的,则需要调整索引变量以避免丢失条目或返回两次。即使一切都正确,在当前位置之前同时插入的列表条目也不会显示。

  • 如果#1情况下的修改是由不同的线程执行的,则很难正确同步。核心问题是 get(int)size() 是单独的操作。即使它们是单独同步的,也没有什么可以阻止其他线程在 sizeget 调用之间修改列表。

简而言之,迭代正在同时修改的列表是很棘手的,应该避免......除非您真的知道自己在做什么

In response to this comment from the OP.

However, #1 is required when updating (if not just mutating the current item or building the results as a new list) and comes with the index. Since the List<> is an ArrayList<> in this case, the get() (and size()) is O(1), but that isn't the same for all List-contract types.

Lets look at these issues:

It is certainly true that get(int) is not O(1) for all implementations of the List contract. However, AFAIK, size() is O(1) for all List implementations in java.util. But you are correct that #1 is suboptimal for many List implementations. Indeed, for lists like LinkedList where get(int) is O(N), the #1 approach results in a O(N^2) list iteration.

In the ArrayList case, it is a simple matter to manually hoist the call to size(), assigning it to a (final) local variable. With this optimization, the #1 code is significantly faster than the other cases ... for ArrayLists.

Your point about changing the list while iterating the elements raises a number of issues:

  • If you do this with a solution that explicitly or implicitly uses iterators, then depending on the list class you may get ConcurrentModificationExceptions. If you use one of the concurrent collection classes, you won't get the exception, but the javadocs state that the iterator won't necessarily return all of the list elements.

  • If you do this using the #1 code (as is) then, you have a problem. If the modification is performed by the same thread, you need to adjust the index variable to avoid missing entries, or returning them twice. Even if you get everything right, a list entry concurrently inserted before the current position won't show up.

  • If the modification in the #1 case is performed by a different thread, it hard to synchronize properly. The core problem is that get(int) and size() are separate operations. Even if they are individually synchronized, there is nothing to stop the other thread from modifying the list between a size and get call.

In short, iterating a list that is being concurrently modified is tricky, and should be avoided ... unless you really know what you are doing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文