简体   繁体   English

在java中修改List的每个项目

[英]Modifying each item of a List in java

I'm just starting to work with lists in java. 我刚开始使用java中的列表。 I'm wondering what the recommended method to modify each element of a list would be? 我想知道修改列表的每个元素的推荐方法是什么?

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? 有没有更好的方法在java中完成这项工作? And is any of the below methods recommended over the other, or are both on the same level? 并且以下任何一种方法都推荐在另一种方法上,或者两者都处于同一水平?

//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");
}

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. Java集合框架中有许多集合,每个集合都针对特定需求进行了优化。 Many people use the ArrayList, which internally uses an array. 许多人使用ArrayList,它在内部使用数组。 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 . 只要元素的数量随时间变化不大,并且具有get,set和size 在此特定类型的列表上的恒定时间操作的特殊好处,这是很好的。

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(索引)和删除(索引) 不是!

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. 测试表明,使用迭代器和get(i)对于ArrayList,但在LinkedList上有很大的时间差(有利于迭代器)之间几乎没有时间差。

EDIT: If you know that size() , get(index) and set(index, value) are all constant time operations for the operations you're using (eg for ArrayList ), I would personally just skip the iterators in this case: 编辑: 如果你知道size()get(index)set(index, value)都是你正在使用的操作的常量时间操作(例如对于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 first match). 您的第一种方法效率低且可能不正确(因为indexOf可能返回错误的值 - 它将返回第一个匹配项)。 Your second approach is very confusing - the fact that you call next() twice and previous once makes it hard to understand in my view. 你的第二种方法非常令人困惑 - 事实上你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. 当然,使用List.set(index, value)任何方法对于没有恒定时间索引写访问的列表来说效率低下。 As TwoThe noted, using ListIterator.set(value) is much better. 正如Two所指出的,使用ListIterator.set ListIterator.set(value)要好得多。 TwoThe's approach of using a ListIterator is a better general purpose approach. 使用的TwoThe的做法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 changing the list, you don't need to worry about it. 如果您不更改列表,则无需担心。

Internally there in Iterator for for-each implementation. Iterator内部进行for-each实现。 So there is no deference between these two cases. 所以这两种情况之间没有差别。 But if you trying to modify element it will throws ConcurrentModificationException . 但是如果你试图修改元素,它将throws ConcurrentModificationException

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM