Почему не меняется префикс до приращения записи в итерационной части цикла for?
Почему это
int x = 2;
for (int y =2; y>0;y--){
System.out.println(x + " "+ y + " ");
x++;
}
печатает то же самое, что и это?
int x = 2;
for (int y =2; y>0;--y){
System.out.println(x + " "+ y + " ");
x++;
}
Насколько я понимаю, пост-инкремент сначала используется "как есть", затем увеличивается. Сначала добавляется предварительный инкремент, а затем используется. Почему это не относится к телу цикла for?
Ответы
Ответ 1
Цикл эквивалентен:
int x = 2;
{
int y = 2;
while (y > 0)
{
System.out.println(x + " "+ y + " ");
x++;
y--; // or --y;
}
}
Как видно из чтения этого кода, не имеет значения, используете ли вы оператор post или pre декремента в третьем разделе цикла for.
В общем случае любой для цикла вида:
for (ForInit ; Expression ; ForUpdate)
forLoopBody();
точно эквивалентен циклу while:
{
ForInit;
while (Expression) {
forLoopBody();
ForUpdate;
}
}
Цикл for более компактен и, таким образом, легче анализировать такую общую идиому.
Ответ 2
Чтобы визуализировать эти вещи, разверните цикл for в цикл while:
for (int i = 0; i < 5; ++i) {
do_stuff(i);
}
Расширяется до:
int i = 0;
while (i < 5) {
do_stuff(i);
++i;
}
Если вы выполняете пост-инкремент или предварительный инкремент на счетчике циклов, это не имеет значения, потому что результат выражения инкремента (либо значение до, либо после инкремента) не используется в пределах одного и того же оператора.
Ответ 3
Нет никакой разницы в показателях производительности, если это вас беспокоит. Он может использоваться только неправильно (и, следовательно, чувствителен к ошибкам), когда вы используете его в течение приращения.
Рассмотрим:
for (int i = 0; i < 3;)
System.out.print(++i + ".."); //prints 1..2..3
for (int i = 0; i < 3;)
System.out.print(i++ + ".."); //prints 0..1..2
или
for (int i = 0; i++ < 3;)
System.out.print(i + ".."); //prints 1..2..3
for (int i = 0; ++i < 3;)
System.out.print(i + ".."); //prints 1..2
Интересной деталью является то, что нормальная идиома должна использовать i++
в выражении приращения оператора for
и что компилятор Java будет скомпилировать его, как если бы использовался ++i
.
Ответ 4
++ я и я ++ имеют значение при использовании в сочетании с оператором присваивания, таким как int num = я ++ и int num = ++ я или другие выражения.
В вышеприведенном цикле FOR существует только дополнительное условие, поскольку оно не используется в сочетании с каким-либо другим выражением, оно не имеет никакого значения. В этом случае это будет означать только я = я + 1.
Ответ 5
Этот цикл такой же, как этот цикл while
:
int i = 0;
while(i < 5)
{
// LOOP
i++; // Or ++i
}
Итак, да, это должно быть одно и то же.
Ответ 6
Потому что это утверждение просто на его собственном. Порядок приращения там не имеет значения.
Ответ 7
Эти два случая эквивалентны, потому что значение я сравнивается после выполнения инструкции increment. Однако, если вы сделали
if (i++ < 3)
против
if (++i < 3)
вам придется беспокоиться о порядке вещей.
И если вы сделали
i = ++i + i++;
тогда вы просто орехи.
Ответ 8
Потому что ничто в ваших примерах не использует значение, возвращенное из пре-или пост-приращений. Попробуйте обернуть System.out.println()
вокруг ++x
и x++
, чтобы увидеть разницу.
Ответ 9
В главе глава Java Language Specification для циклов петель:
BasicForStatement:
for ( ForInit ; Expression ; ForUpdate ) Statement
... если часть ForUpdate присутствует, выражения вычисляются в последовательность слева направо; их значения, если они есть, отбрасываются.... Если часть ForUpdate отсутствует, никаких действий не предпринимается.
(выделение - мое).
Ответ 10
Результат тот же, поскольку элемент "increment" в "for (initial; compare; increment)" не использует результат инструкции, он просто полагается на побочный эффект выражения, который в этот случай увеличивает значение "i", что в обоих случаях одинаково.
Ответ 11
Проверка выполняется до вычисления аргумента increment. Операция "increment" выполняется в конце цикла, даже если она была объявлена в начале.
Ответ 12
Попробуйте этот пример:
int i = 6;
System.out.println(i++);
System.out.println(i);
i = 10;
System.out.println(++i);
System.out.println(i);
Вы должны уметь выработать то, что он делает.
Ответ 13
Поскольку значение y
вычисляется в выражении for
, а значение x
вычисляется в его собственной строке, но в System.out.println
они ссылаются только на.
Если вы уменьшаетесь внутри System.out.println
, вы получите другой результат.
System.out.println(y--);
System.out.println(--y);
Ответ 14
Здесь есть много хороших ответов, но в случае, если это поможет:
Подумайте о y-- и -y как выражениях с побочными эффектами или о выражении, сопровождаемом выражением. y-- так (подумайте об этих примерах как псевдо-сборке):
decrement y
return y
и --y делает следующее:
store y into t
decrement y
load t
return t
В примере вашего цикла вы выбрасываете возвращаемое значение в любом случае и полагаетесь только на побочный эффект (проверка цикла происходит ПОСЛЕ выполнения инструкции декремента, она не принимает/не проверяет значение, возвращаемое декрементом).
Ответ 15
Если цикл for
использовал результат выражения i++
или ++i
для чего-то, тогда это было бы правдой, но это не так, это просто потому, что его побочный эффект.
Вот почему вы также можете поместить здесь метод void
, а не только числовое выражение.
Ответ 16
Приращение выполняется как независимый оператор. Так
у -;
и
- у;
эквивалентны друг другу, и оба эквивалентны
y = y - 1;
Ответ 17
Потому что это:
int x = 2;
for (int y =2; y>0; y--){
System.out.println(x + " "+ y + " ");
x++;
}
Эффективно переводится компилятором на это:
int x = 2;
int y = 2
while (y > 0){
System.out.println(x + " "+ y + " ");
x++;
y--;
}
Как вы видите, использование y--
или --y
не приводит к какой-либо разнице. Было бы полезно, если бы вы написали свой цикл следующим образом:
int x = 2;
for (int y = 3; --y > 0;){
System.out.println(x + " "+ y + " ");
x++;
}
Это приведет к тому же результату, что и ваши два варианта цикла, но переход от --y
в y--
приведет к поломке вашей программы.
Ответ 18
Это вопрос вкуса. Они делают то же самое.
Если вы посмотрите на код классов java, вы увидите, что для циклов с последующим приращением вы увидите.
Ответ 19
в вашем случае, это то же самое, никакой разницы вообще.
Ответ 20
Вы правы. Разницу можно увидеть в этом случае:
for(int i = 0; i < 5; )
{
System.out.println("i is : " + ++i);
}
Ответ 21
Да, он делает это последовательно. Intialisation, затем условие оценки, и если true, то выполняется тело, а затем увеличивается.
Префикс и постфиксная разница будут заметны только тогда, когда вы выполняете операцию присваивания с помощью Приращения/Уменьшения.
Ответ 22
Нет различий, потому что каждая часть аргументов "arguments" является разделяемыми операторами.
И интересно то, что компилятор может решить заменить простые пост-инкременции на предварительные инкрементации, и это не изменит вещь на код.
Ответ 23
Они НЕ ведут себя одинаково. Конструкция с я ++ немного медленнее, чем с ++ i, потому что первая включает в себя возврат как старых, так и новых значений i. С другой стороны, последнее возвращает только старое значение i.
Затем, вероятно, компилятор делает небольшую магию и меняет любой изолированный я ++ на ++ i по соображениям производительности, но с точки зрения необработанного алгоритма они не строго то же самое.
Ответ 24
Там много похожих сообщений в Stackoverflow:
Однако, похоже, ваш вопрос более общий, поскольку он не является специфическим для какого-либо языка или компилятора. Большинство из вышеперечисленных вопросов касаются конкретного языка/компилятора.
Вот краткое изложение:
- если мы говорим о C/С++/Java (возможно, С# тоже) и современном компиляторе:
- если
i
- целое число (const int
, int
и т.д.):
- тогда компилятор в основном заменит
i++
на ++i
, потому что они семантически идентичны и поэтому не изменят вывод. это можно проверить, проверив сгенерированный код/байт-код (для Java я использую jclasslib просмотрщик байтов).
- еще:
- еще:
- все ставки отключены, поскольку компилятор не может гарантировать, что они семантически идентичны, поэтому он не пытается оптимизировать.
Итак, если у вас есть класс на С++, который переопределяет операторы постфикса и префикса (например, std::iterator
), эта оптимизация выполняется редко, если вообще когда-либо делается.
Вкратце:
- Знайте, что вы говорите, и говорите, что вы имеете в виду. Для инкрементной части циклов
for
вы почти всегда хотите версию префикса (т.е. ++i
).
- Компилятор switchcheroo между
++i
и i++
не всегда может быть выполнен, но он попытается сделать это для вас, если это возможно.
Ответ 25
в цикле, первая инициализация, затем проверка условий, затем выполнение, после этого приращения/уменьшения. поэтому pre/post increment/decment не влияет на программный код.
Ответ 26
О я ++ (post-incrementation) vs. ++ я (pre-incrementation) @me: "В обоих случаях выражение получает оценку, и результат используется для проверки на условие. В случае pre-increment, выражение приращения увеличивает значение переменной и возвращает результирующее значение.Для последующего приращения выражение increment также увеличивает эту переменную, но возвращает предыдущее значение. В результате pre-increment сравнивается с приращенным значением, тогда как приращение сравнивается с исходным значением, и в обоих случаях переменная была увеличена, когда условие проверено." - tdammers