Изменение каждого элемента списка в java

Я только начинаю работать со списками в 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");
}

Ответы

Ответ 1

Вторая версия будет лучше. Внутри они совпадают в конце, но второй фактически позволяет вам изменять список, в то время как первый будет вызывать исключение 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, который внутренне использует массив. Это прекрасно, если количество элементов не изменяется со временем и имеет особое преимущество, которое получает, устанавливает и определяет размер операций с постоянным временем для этого конкретного типа списка.

Однако существуют другие типы списков, где это неверно. Например, если у вас есть список, который постоянно растет и/или сокращается, гораздо лучше использовать LinkedList, потому что в отличие от ArrayList add (element) является постоянной операцией времени, но добавляет (index, element), get ( index) и remove (index) не являются!

Чтобы получить позицию конкретного индекса, список должен пройти от первого/последнего до тех пор, пока не будет найден конкретный элемент. Поэтому, если вы сделаете это в цикле, это будет соответствовать следующему псевдокоду:

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) для ArrayList существует небольшая разница во времени, но огромная разница во времени (в пользу итератора) в LinkedList.

Ответ 2

EDIT: Если, вы знаете, что size(), get(index) и set(index, value) - все операции с постоянным временем для используемых операций (например, для ArrayList), я лично просто пропустите итераторы в этом случае:

for (int i = 0; i < list.size(); i++) {
    list.set(i, list.get(i) + " blah");
}

Ваш первый подход неэффективен и потенциально неверен (поскольку indexOf может вернуть неправильное значение - он вернет первое совпадение). Ваш второй подход очень сбивает с толку - тот факт, что вы дважды вызываете next() и previous, затрудняет понимание на мой взгляд.

Любой подход с использованием List.set(index, value) будет неэффективен для списка, который, конечно, не имеет постоянный индексный доступ на запись. Как указано TwoThe, использование ListIterator.set(value) намного лучше. TwoThe подход использования ListIterator является лучшим универсальным подходом.

Тем не менее, другой альтернативой во многих случаях было бы изменение дизайна, чтобы проектировать один список на другой вместо этого - либо в виде, либо в виде материала. Когда вы не меняете список, вам не нужно беспокоиться об этом.

Ответ 3

Внутри внутри Iterator для for-each реализации. Поэтому между этими двумя случаями нет никакого почтения. Но если вы попытаетесь изменить элемент, то он будет throws ConcurrentModificationException.

Ответ 4

Я получил свою работу таким образом

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