在java中修改List的每一项
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20000443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Modifying each item of a List in java
提问by Shisa
I'm just starting to work with lists in java. I'm wondering what the recommended method to modify each element of a list would be?
我刚刚开始使用 java 中的列表。我想知道修改列表中每个元素的推荐方法是什么?
I've been able to get it done with both the following methods, but they both seem fairly unelegant. Is there any better way to get this done in java? And is any of the below methods recommended over the other, or are both on the same level?
我已经能够使用以下两种方法完成它,但它们看起来都相当不优雅。有没有更好的方法在java中完成这项工作?是否推荐以下任何一种方法,或者两者都在同一水平上?
//Modifying with foreach
for (String each : list)
{
list.set(list.indexOf(each), each+ " blah");
}
//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next())
{
i.next();
list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
采纳答案by TwoThe
The second version would be better. Internally they are the same in the end, but the second actually allows you to modify the list, while the first one will throw a ConcurrentModificationException.
第二个版本会更好。在内部它们最终是相同的,但第二个实际上允许您修改列表,而第一个将抛出 ConcurrentModificationException。
But then you are using the Iterator in a wrong way. Here is how you do it correctly:
但是随后您以错误的方式使用了迭代器。以下是您如何正确执行此操作:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
The iterator is the one that needs to modify the list as it is the only one that knows how to do that properly without getting confused about the list elements and order.
迭代器是需要修改列表的迭代器,因为它是唯一知道如何正确地执行此操作而不会对列表元素和顺序感到困惑的迭代器。
Edit:Because I see this in all comments and the other answers:
编辑:因为我在所有评论和其他答案中都看到了这一点:
Why you should not use list.get, list.set and list.size in a loop
为什么不应该在循环中使用 list.get、list.set 和 list.size
There are many collections in the Java collections framework, each on optimized for specific needs. Many people use the ArrayList, which internally uses an array. This is fine as long as the amount of elements does not change much over time and has the special benefit that get, set and size are constant time operations on this specific type of list.
Java 集合框架中有许多集合,每个集合都针对特定需求进行了优化。许多人使用 ArrayList,它内部使用一个数组。只要元素的数量不会随时间发生太大变化,并且具有特殊的好处,即 get、set 和 size 是这种特定类型的 list 上的恒定时间操作,这很好。
There are however other list types, where this is not true. For example if you have a list that constantly grows and/or shrinks, it is much better to use a LinkedList, because in contrast to the ArrayList add(element) is a constant time operation, but add(index, element), get(index) and remove(index) are not!
然而,还有其他列表类型,但事实并非如此。例如,如果您有一个不断增长和/或缩小的列表,那么使用 LinkedList 会好得多,因为与 ArrayList 相比,add(element) 是一个恒定时间操作,但 add(index, element), get( index) 和 remove(index)不是!
To get the position of the specific index, the list needs to be traversed from the first/last till the specific element is found. So if you do that in a loop, this is equal to the following pseudo-code:
要获取特定索引的位置,需要从第一个/最后一个遍历列表,直到找到特定元素。因此,如果您在循环中执行此操作,则这等于以下伪代码:
for (int index = 0; index < list.size(); ++index) {
Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}
The Iterator is an abstract way to traverse a list and therefore it can ensure that the traversal is done in an optimal way for each list. Test show that there is little time difference between using an iterator and get(i) for an ArrayList, but a huge time difference (in favor for the iterator) on a LinkedList.
Iterator 是一种遍历列表的抽象方法,因此它可以确保以最佳方式为每个列表完成遍历。测试表明,对于 ArrayList 使用迭代器和 get(i) 之间几乎没有时间差异,但在 LinkedList 上使用巨大的时间差异(有利于迭代器)。
回答by Ruchira Gayan Ranaweera
Internally there in Iterator
for for-each
implementation. So there is no deference between these two cases. But if you trying to modify element it will throws
ConcurrentModificationException
.
在内部Iterator
进行for-each
实施。所以这两种情况没有区别。但是如果你试图修改元素它会throws
ConcurrentModificationException
。
回答by Jon Skeet
EDIT: Ifyou know that size()
, get(index)
and set(index, value)
are all constant time operations for the operations you're using (e.g. for ArrayList
), I would personally just skip the iterators in this case:
编辑:如果您知道size()
,get(index)
并且set(index, value)
是您正在使用的操作的所有常量时间操作(例如 for ArrayList
),我个人会在这种情况下跳过迭代器:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
Your first approach is inefficient and potentially incorrect (as indexOf
may return the wrong value - it will return the firstmatch). Your second approach is very confusing - the fact that you call next()
twice and previous
once makes it hard to understand in my view.
您的第一种方法效率低下并且可能不正确(因为indexOf
可能会返回错误的值 - 它会返回第一个匹配项)。您的第二种方法非常令人困惑-在我看来,您调用next()
两次和previous
一次的事实使其难以理解。
Any approach using List.set(index, value)
will be inefficient for a list which doesn't have constant time indexed write access, of course. As TwoThe noted, using ListIterator.set(value)
is much better. TwoThe's approach of using a ListIterator
is a better general purpose approach.
List.set(index, value)
当然,对于没有固定时间索引写访问的列表,任何使用方法都是低效的。正如 TwoThe 指出的那样,使用ListIterator.set(value)
要好得多。TwoThe 使用 a 的方法ListIterator
是一种更好的通用方法。
That said, another alternative in many cases would be to change your design to project one list to another instead - either as a view or materially. When you're not changingthe list, you don't need to worry about it.
也就是说,在许多情况下,另一种选择是更改您的设计以将一个列表投影到另一个列表 - 无论是作为视图还是实体。当您不更改列表时,您无需担心。
回答by Hodeifa Baswel
I got mine working this way
我以这种方式工作
String desiredInvoice="abc-123";
long desiredAmount=1500;
for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
MyPurchase item = it.next();
if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
item.setPaymentAmount(desiredAmount);
it.set(item);
break;
}
}