Как "final int i"работает внутри цикла Java for?



Я был удивлен, увидев, что следующий фрагмент кода Java скомпилирован и запущен:



for(final int i : listOfNumbers) {
System.out.println(i);
}


где listOfNumbers-это массив целых чисел.



Я думал, что окончательные декларации были назначены только один раз. Компилятор создает целочисленный объект и изменяет то, на что он ссылается?

624   2  

2 ответов:

представьте, что стенография выглядит примерно так:

for (Iterator<Integer> iter = listOfNumbers.iterator(); iter.hasNext(); )
{
    final int i = iter.next();
    {
        System.out.println(i);
    }
}

см. @TravisG для объяснения соответствующих правил определения области. Единственная причина, по которой вы будете использовать переменную final loop, - это если вам нужно закрыть ее в анонимном внутреннем классе.

import java.util.Arrays;
import java.util.List;

public class FinalLoop {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[] { 0,1,2,3,4 });
        Runnable[] runs = new Runnable[list.size()];

        for (final int i : list) {
            runs[i] = new Runnable() {
                    public void run() {
                        System.out.printf("Printing number %d\n", i);
                    }
                };
        }

        for (Runnable run : runs) {
            run.run();
        }
    }
}

переменная цикла не находится в области Runnable, когда она выполняется, только когда она создается. Без final ключевое слово переменная цикла не будет видна для Runnable, когда она в конечном итоге запускается. Даже если бы это было так, это было бы одинаковое значение для всех в Runnables.

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

в ответ на @mafutrct:

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

в случае переменной цикла использование final может использоваться для передачи одной из двух вещей: одно назначение; или закрытие. Тривиальное сканирование цикла скажет вам, если цикл переменная переназначается; однако из-за чередования двух путей выполнения при создании замыкания может быть легко пропустить, что замыкание предназначено для захвата переменной. Если, конечно, вы никогда не используете final только для указания намерения захватить, и в этот момент читателю становится очевидно, что происходит.

Comments

    Ничего не найдено.