我刚开始使用java中的列表。我想知道修改列表中每个元素的推荐方法是什么?
我已经能够用以下两种方法完成它,但它们看起来都相当不优雅。有没有更好的方法在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");
}
答案 0 :(得分:20)
第二个版本会更好。在内部它们最终是相同的,但第二个实际上允许你修改列表,而第一个实际上会抛出一个ConcurrentModificationException。
但是你以错误的方式使用迭代器。这是你如何正确地做到这一点:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
迭代器是需要修改列表的迭代器,因为它是唯一一个知道如何正确执行该操作而不会对列表元素和顺序感到困惑的人。
修改:因为我在所有评论和其他答案中都看到了这一点:
为什么你不应该在循环中使用list.get,list.set和list.size
Java集合框架中有许多集合,每个集合都针对特定需求进行了优化。许多人使用ArrayList,它在内部使用数组。只要元素的数量不会随着时间的推移发生太大变化,并且get,set和size在此特定类型的列表上持续时间操作具有特殊优势,这是很好的。
但是有其他列表类型,这不是真的。例如,如果你有一个不断增长和/或收缩的列表,那么使用LinkedList要好得多,因为与ArrayList相比,add(element)是一个常量时间操作,但是add(index,element),get(索引)和删除(索引)不是!
要获取特定索引的位置,需要从第一个/最后一个遍历列表,直到找到特定元素。因此,如果您在循环中执行此操作,则等于以下伪代码:
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(); }) );
}
迭代器是一种遍历列表的抽象方法,因此它可以确保遍历以每种列表的最佳方式完成。测试显示使用迭代器和get(i)之间的时间差异很小,但是在LinkedList上有很大的时间差异(有利于迭代器)。
答案 1 :(得分:10)
编辑:如果您知道size()
,get(index)
和set(index, value)
都是您正在使用的操作的常量时间操作(例如ArrayList
1}}),我个人会在这种情况下跳过迭代器:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
您的第一种方法效率低且可能不正确(因为indexOf
可能返回错误的值 - 它将返回第一个匹配)。你的第二种方法非常令人困惑 - 你曾两次致电next()
并且previous
一次,这让我很难理解。
当然,使用List.set(index, value)
的任何方法对于没有恒定时间索引写访问权的列表来说效率低下。正如Two所指出的那样,使用ListIterator.set(value)
要好得多。使用ListIterator
的两种方法是一种更好的通用方法。
尽管如此,在许多情况下,另一种选择是将您的设计更改为将一个列表投射到另一个列表 - 无论是视图还是实质性。如果您没有更改列表,则无需担心。
答案 2 :(得分:0)
内部Iterator
for-each
实施throws
。所以这两种情况之间没有差别。但是,如果您尝试修改元素,它将ConcurrentModificationException
{{1}}。
答案 3 :(得分:0)
我让我这样工作
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;
}
}