Почему не делает изменения пред к инкременту сообщения в итеративной части для цикла, имеют значение?

Почему делает это

 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++;
        }

Настолько далеко, как я понимаю, что постинкремент сначала используется, "поскольку он" тогда увеличен. Преинкремент, сначала добавляется и затем используется. Почему это не относится к телу для цикла?

38
задан andandandand 16 December 2009 в 22:17
поделиться

24 ответа

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.

58
ответ дан 27 November 2019 в 03:00
поделиться

The increment is executed as an independent statement. So

y--;

and

--y;

are equivalent to each other, and both equivalent to

y = y - 1;

0
ответ дан 27 November 2019 в 03:00
поделиться

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.

0
ответ дан 27 November 2019 в 03:00
поделиться

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);
1
ответ дан 27 November 2019 в 03:00
поделиться

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).

3
ответ дан 27 November 2019 в 03:00
поделиться

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.

3
ответ дан 27 November 2019 в 03:00
поделиться

Because that statement is just on it's own. The order of the increment doesn't matter there.

5
ответ дан 27 November 2019 в 03:00
поделиться

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).

1
ответ дан 27 November 2019 в 03:00
поделиться

в вашем случае то же самое, без разницы.

0
ответ дан 27 November 2019 в 03:00
поделиться

Нет никакой разницы в производительности, если вас это беспокоит. Он может быть использован неправильно (и, следовательно, чувствителен к ошибкам) ​​только тогда, когда вы используете 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 .

17
ответ дан 27 November 2019 в 03:00
поделиться

Это дело вкуса. Они делают одни и те же вещи.

Если вы посмотрите на код java-классов, то увидите там for-петли с пост-инкрементом.

0
ответ дан 27 November 2019 в 03:00
поделиться

Эти два случая эквивалентны, потому что значение i сравнивается после выполнения оператора приращения. Однако, если вы сделали

if (i++ < 3) 

вместо

if (++i < 3)

, вам придется беспокоиться о порядке вещей.

А если вы сделали

i = ++i + i++;

, то вы просто чокнутый.

4
ответ дан 27 November 2019 в 03:00
поделиться

Проверка выполняется до того, как вычисляется аргумент приращения. . Операция «приращения» выполняется в конце цикла, даже если она объявлена ​​в начале.

2
ответ дан 27 November 2019 в 03:00
поделиться

В Stackoverflow есть много похожих сообщений:

Однако, похоже, ваш вопрос более общий, потому что он не специфичен для какого-либо языка или компилятора. Большинство приведенных выше вопросов относятся к конкретному языку / компилятору.

Вот краткое изложение:

  • если мы говорим о C / C ++ / Java (возможно, тоже C #) и современном компиляторе:
    • , если i является целым числом ( const int , int и т. Д.):
      • , то компилятор в основном заменит i ++ на ++ i , потому что они семантически идентичны и поэтому он не изменяет вывод. это можно проверить, проверив сгенерированный код / ​​байт-код (для Java я использую программу просмотра байт-кода jclasslib ).
    • else:
  • else:
    • все ставки отключены, потому что компилятор не может гарантировать, что они семантически идентичны, поэтому он не пытается оптимизировать.

Итак, если у вас есть класс на C ++, который переопределяет постфиксные и префиксные операторы (например, std :: iterator ), такая оптимизация выполняется редко, если вообще выполняется.

Вкратце:

  • Имейте в виду то, что вы говорите, и говорите то, что вы имеете в виду. Для части приращения для циклов вам почти всегда нужна версия с префиксом (то есть ++ i ).
  • Переключение компилятора между ++ i и i ++ не всегда может быть выполнено, но он попытается сделать это за вас, если сможет.
0
ответ дан 27 November 2019 в 03:00
поделиться

Они НЕ ведут себя одинаково. Конструкция с i ++ немного медленнее, чем конструкция с ++ i , потому что первая включает в себя возврат как старых, так и новых значений i . С другой стороны, последний возвращает только старое значение i .

Затем, вероятно, компилятор совершит небольшое волшебство и преобразует любой изолированный i ++ в ++ i по соображениям производительности, но с точки зрения исходного алгоритма они не совсем такие же .

0
ответ дан 27 November 2019 в 03:00
поделиться

Вы правы. Разницу можно увидеть в этом случае:

for(int i = 0; i < 5; )
       {
            System.out.println("i is : " + ++i);           
       }
0
ответ дан 27 November 2019 в 03:00
поделиться

Если бы цикл for использовал результат выражения i ++ или ++ i для чего-то, то это было бы правда, но это не так, это просто потому, что его побочный эффект.

Вот почему вы также можете поместить туда метод void , а не только числовое выражение.

1
ответ дан 27 November 2019 в 03:00
поделиться

Попробуйте следующий пример:

int i = 6;
System.out.println(i++);
System.out.println(i);

i = 10;
System.out.println(++i);
System.out.println(i);

Вы должны понять, что он делает из этого.

2
ответ дан 27 November 2019 в 03:00
поделиться

Этот цикл такой же, как этот while цикл:

int i = 0;
while(i < 5)
{
     // LOOP
     i++; // Or ++i
}

Так что да, он должен быть таким же.

6
ответ дан 27 November 2019 в 03:00
поделиться

Чтобы визуализировать эти вещи, разверните цикл for до цикла while:

for (int i = 0; i < 5; ++i) {
    do_stuff(i);
}

Расширяется до:

int i = 0;
while (i < 5) {
    do_stuff(i);
    ++i;
}

Независимо от того, выполняете ли вы постинкрементное или предварительное приращение на счетчике цикла, не имеет значение, потому что результат выражения приращения (значение до или после приращения) не используется в одном и том же операторе.

29
ответ дан 27 November 2019 в 03:00
поделиться

Да, последовательно. Инициализация, затем условие оценки и, если истинно, выполнение тела с последующим увеличением.

Разница между префиксом и постфиксом будет заметна только тогда, когда вы выполните операцию присваивания с помощью увеличения / уменьшения.

0
ответ дан 27 November 2019 в 03:00
поделиться

Вывод такой же, потому что элемент «приращение» в «for (initial; compare; инкремент) 'не использует результат оператора, он просто полагается на побочный эффект оператора, который в данном случае увеличивает' i ', который является то же самое в обоих случаях.

3
ответ дан 27 November 2019 в 03:00
поделиться

++ i и i ++ имеют значение при использовании в сочетании с оператором присваивания, например int num = i ++ и int num = ++ i или другими выражениями. В приведенном выше цикле FOR существует только условие приращения, поскольку оно не используется в сочетании с каким-либо другим выражением, это не имеет никакого значения. В этом случае это будет означать только i = i + 1.

13
ответ дан 27 November 2019 в 03:00
поделиться

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

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

0
ответ дан 27 November 2019 в 03:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: