Почему делает это
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++;
}
Настолько далеко, как я понимаю, что постинкремент сначала используется, "поскольку он" тогда увеличен. Преинкремент, сначала добавляется и затем используется. Почему это не относится к телу для цикла?
The loop is equivalent to:
int x = 2;
{
int y = 2;
while (y > 0)
{
System.out.println(x + " "+ y + " ");
x++;
y--; // or --y;
}
}
As you can see from reading that code, it doesn't matter whether you use the post or pre decrement operator in the third section of the for loop.
More generally, any for loop of the form:
for (ForInit ; Expression ; ForUpdate)
forLoopBody();
is exactly equivalent to the while loop:
{
ForInit;
while (Expression) {
forLoopBody();
ForUpdate;
}
}
The for loop is more compact, and thus easier to parse for such a common idiom.
The increment is executed as an independent statement. So
y--;
and
--y;
are equivalent to each other, and both equivalent to
y = y - 1;
Because this:
int x = 2;
for (int y =2; y>0; y--){
System.out.println(x + " "+ y + " ");
x++;
}
Effectively gets translated by the compiler to this:
int x = 2;
int y = 2
while (y > 0){
System.out.println(x + " "+ y + " ");
x++;
y--;
}
As you see, using y--
or --y
doesn't result in any difference. It would make a difference if you wrote your loop like this, though:
int x = 2;
for (int y = 3; --y > 0;){
System.out.println(x + " "+ y + " ");
x++;
}
This would yield the same result as your two variants of the loop, but changing from --y
to y--
here would break your program.
Because the value of y
is calculated in for
statement and the value of x
is calculated in its own line, but in the System.out.println
they are only referenced.
If you decremented inside System.out.println
, you would get different result.
System.out.println(y--);
System.out.println(--y);
From the Java Language Specification chapter on for loops:
BasicForStatement:
for ( ForInit ; Expression ; ForUpdate ) Statement
... if the ForUpdate part is present, the expressions are evaluated in sequence from left to right; their values, if any, are discarded. ... If the ForUpdate part is not present, no action is taken.
(highlight is mine).
Because nothing in your examples is using the value returned from the pre- or post-increments. Try wrapping a System.out.println()
around the ++x
and x++
to see the difference.
Because that statement is just on it's own. The order of the increment doesn't matter there.
There are a lot of good answers here, but in case this helps:
Think of y-- and --y as expressions with side effects, or a statement followed by an expression. y-- is like this (think of these examples as pseudo-assembly):
decrement y
return y
and --y does this:
store y into t
decrement y
load t
return t
In your loop example, you are throwing away the returned value either way, and relying on the side effect only (the loop check happens AFTER the decrement statement is executed; it does not receive/check the value returned by the decrement).
Нет никакой разницы в производительности, если вас это беспокоит. Он может быть использован неправильно (и, следовательно, чувствителен к ошибкам) только тогда, когда вы используете it во время приращения.
Обратите внимание:
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
.
Это дело вкуса. Они делают одни и те же вещи.
Если вы посмотрите на код java-классов, то увидите там for-петли с пост-инкрементом.
Эти два случая эквивалентны, потому что значение i сравнивается после выполнения оператора приращения. Однако, если вы сделали
if (i++ < 3)
вместо
if (++i < 3)
, вам придется беспокоиться о порядке вещей.
А если вы сделали
i = ++i + i++;
, то вы просто чокнутый.
Проверка выполняется до того, как вычисляется аргумент приращения. . Операция «приращения» выполняется в конце цикла, даже если она объявлена в начале.
В Stackoverflow есть много похожих сообщений:
Однако, похоже, ваш вопрос более общий, потому что он не специфичен для какого-либо языка или компилятора. Большинство приведенных выше вопросов относятся к конкретному языку / компилятору.
Вот краткое изложение:
i
является целым числом ( const int
, int
и т. Д.):
i ++
на ++ i
, потому что они семантически идентичны и поэтому он не изменяет вывод. это можно проверить, проверив сгенерированный код / байт-код (для Java я использую программу просмотра байт-кода jclasslib ). Итак, если у вас есть класс на C ++, который переопределяет постфиксные и префиксные операторы (например, std :: iterator
), такая оптимизация выполняется редко, если вообще выполняется.
Вкратце:
для циклов
вам почти всегда нужна версия с префиксом (то есть ++ i
). ++ i
и i ++
не всегда может быть выполнено, но он попытается сделать это за вас, если сможет. Они НЕ ведут себя одинаково. Конструкция с i ++ немного медленнее, чем конструкция с ++ i , потому что первая включает в себя возврат как старых, так и новых значений i . С другой стороны, последний возвращает только старое значение i .
Затем, вероятно, компилятор совершит небольшое волшебство и преобразует любой изолированный i ++ в ++ i по соображениям производительности, но с точки зрения исходного алгоритма они не совсем такие же .
Вы правы. Разницу можно увидеть в этом случае:
for(int i = 0; i < 5; )
{
System.out.println("i is : " + ++i);
}
Если бы цикл for
использовал результат выражения i ++
или ++ i
для чего-то, то это было бы правда, но это не так, это просто потому, что его побочный эффект.
Вот почему вы также можете поместить туда метод void
, а не только числовое выражение.
Попробуйте следующий пример:
int i = 6;
System.out.println(i++);
System.out.println(i);
i = 10;
System.out.println(++i);
System.out.println(i);
Вы должны понять, что он делает из этого.
Этот цикл такой же, как этот while
цикл:
int i = 0;
while(i < 5)
{
// LOOP
i++; // Or ++i
}
Так что да, он должен быть таким же.
Чтобы визуализировать эти вещи, разверните цикл for до цикла while:
for (int i = 0; i < 5; ++i) {
do_stuff(i);
}
Расширяется до:
int i = 0;
while (i < 5) {
do_stuff(i);
++i;
}
Независимо от того, выполняете ли вы постинкрементное или предварительное приращение на счетчике цикла, не имеет значение, потому что результат выражения приращения (значение до или после приращения) не используется в одном и том же операторе.
Да, последовательно. Инициализация, затем условие оценки и, если истинно, выполнение тела с последующим увеличением.
Разница между префиксом и постфиксом будет заметна только тогда, когда вы выполните операцию присваивания с помощью увеличения / уменьшения.
Вывод такой же, потому что элемент «приращение» в «for (initial; compare; инкремент) 'не использует результат оператора, он просто полагается на побочный эффект оператора, который в данном случае увеличивает' i ', который является то же самое в обоих случаях.
++ i и i ++ имеют значение при использовании в сочетании с оператором присваивания, например int num = i ++ и int num = ++ i или другими выражениями. В приведенном выше цикле FOR существует только условие приращения, поскольку оно не используется в сочетании с каким-либо другим выражением, это не имеет никакого значения. В этом случае это будет означать только i = i + 1.
Нет никаких различий, потому что каждая часть аргументов for - это отдельные операторы.
И что интересно, компилятор может решить заменить простые постинкременты на преинкременты, и это ничего не изменит в коде.