Как "final int i"работает внутри цикла Java for?
Я был удивлен, увидев, что следующий фрагмент кода Java скомпилирован и запущен:
for(final int i : listOfNumbers) {
System.out.println(i);
}
где listOfNumbers-это массив целых чисел.
Я думал, что окончательные декларации были назначены только один раз. Компилятор создает целочисленный объект и изменяет то, на что он ссылается?
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