Вопрос

На этот вопрос уже есть ответ здесь:

Хорошо, итак, я пытаюсь выполнить итерацию по ArrayList и удалить определенный элемент.Однако у меня возникают некоторые проблемы с использованием структуры For-Each like.Когда я запускаю следующий код:

ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)

for(String t : arr)
{
  t = " some other value "; //hoping this would change the actual array
}

for(String t : arr)
{
  System.out.println(t); //however, I still get the same array here
}

Мой вопрос в том, как я могу сделать 't' указателем на 'arr', чтобы я мог изменять значения в цикле для каждого?Я знаю, что мог бы перебирать ArrayList, используя другую структуру, но эта выглядит такой чистой и читаемой, что было бы просто неплохо иметь возможность сделать 't' указателем.

Все комментарии приветствуются!Даже если ты скажешь, что я должен просто смириться с этим и использовать другую конструкцию.

Это было полезно?

Решение

Я думаю, что лучшим подходом может быть использование цикла for .

    ArrayList<String> arr = new ArrayList<String>();

    for (int i = 0; i < arr.size(); i++) {

        String t = arr.get(i);

        if (// your condition is met) {
            arr.set(i, "your new value");
        }
    }

Другие советы

Проблема в том, что вы пытаетесь изменить область действия цикла ссылка t чтобы он указывал на новый экземпляр String.Это не сработает.Он не ссылается на фактическую запись в arraylist .Вам нужно изменить фактический значение из ссылки.Если String был изменяемым и предоставлял фиктивный set() метод для этого, вы могли бы теоретически сделать

for (String t : arr) {
    t.set("some other value");
}

или так, но это невозможно, поскольку оно неизменяемо.Лучше получить дескриптор точки входа в самом массиве, используя обычный for петля:

for (int i = 0; i < arr.size(); i++) {
    arr.set(i, "some other value");
}

Если вы настаиваете на использовании расширенного for цикл, затем вам нужно заменить String Автор: StringBuilder, который является изменяемым:

for (StringBuilder t : arr) {
     t.delete(0, t.length()).append("some other value");
}

Помните, Java - это передача по значению, а не передача по ссылке.

For-each не дает вам указателя индекса, поэтому вы просто не можете использовать его для изменения неизменяемого значения.

Либо используйте цикл for с индексом, либо используйте изменяемый тип (например, StringBuffer, а не String)

Массив объектов (например, строк) в Java представляет собой непрерывный блок, содержащий упорядоченный ряд ссылок.Итак, когда у вас есть массив из 4 строк, то на самом деле у вас есть 4 ссылки, хранящиеся В массиве, и 4 строковых объекта, которые находятся за пределами массива, но на которые ссылаются его 4 элемента.

Что делает конструкция for-each в Java, так это создает локальную переменную и для каждой итерации копирует в эту локальную переменную ссылку из ячейки массива, которая соответствует этой итерации.Когда вы устанавливаете переменную цикла (t = " some other value") вы помещаете ссылку на новую строку, "some other value", в локальную переменную t, а не в массив.

Это контрастирует с некоторыми другими языками (например, Perl), где переменная цикла действует как псевдоним самого элемента массива / списка.

Ваш код переписывается компилятором примерно так:

ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)

for (final Iterator <String> i = arr.iterator(); i.hasNext();) {
    String t;

    t = i.next();
    t = " some other value "; // just changes where t is pointing
}

Чтобы делать то, что вы хотите, вам пришлось бы написать цикл for следующим образом:

for (final ListIterator<String> i = arr.iterator(); i.hasNext();) {
     final String t;

     t = i.next();
     i.set("some other value");
}

У Iterator нет метода set, есть только у ListIterator .

По сути, вы хотите удалить строку t из списка arr.Просто выполните arr.remove(t), и все может быть готово. Но вы не можете сделать это, выполняя итерацию по одному и тому же списку.Вы получите исключение, если попытаетесь изменить список таким образом.

У вас есть два варианта:

  1. клонируйте свой список, выполните итерацию по клонированию и удалите "конкретную" строку из исходного списка
  2. создайте список для кандидатов на удаление, добавьте все "определенные" строки в этот список и, после перебора исходного списка, выполните перебор корзины для мусора и удалите все, что вы собрали здесь, из исходного списка.

Вариант 1 - самый простой, клон может быть сделан следующим образом:

List<String> clone = new ArrayList<String>(arr);

Похоже, вы неправильно понимаете, как объекты / ссылки работают в Java, что является довольно фундаментальным для эффективного использования языка.Однако этот код здесь должен делать то, что вы хотите (приносим извинения за отсутствие объяснений):

ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)

for(int i = 0; i < arr.size(); i++)
{
  arr.set(i, " some other value "); // change the contents of the array
}

for(String t : arr)
{
  System.out.println(t); 
}

Я полагаю, это не имеет отношения к неизменяемому или изменяемому.

 t = " some other value "; //hoping this would change the actual array

t не содержит ссылки на фактический объект.Java копирует значение из arraylist и помещает это значение в t, чтобы значение списка массива не влияло.

HTH

На этот вопрос был дан хороший ответ.И все же вот мое предложение.Внутренний цикл var t виден только там.Это не будет видно за пределами цикла.Вы могли бы сделать t.set() если бы это было не так String.

Используйте StringBuffer вместо простых строк.Таким образом, строка внутри является изменяемой.

Строки являются неизменяемыми.Если бы у вас был изменяемый тип, такой как StringBuilder / Buffer , вы могли бы изменить строку в своей итерации.У тебя есть рекомендации, не забывай.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top