32

これはなぜですか

 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ループの本体に当てはまらないのですか?


  • (初期化;条件;インクリメント):はい。 - Mitch Wheat
  • 両方のバイトコードを生成するためにjavapを使用してください。実験主義者になってください。 - duffymo

27 답변


56

このループは以下と同等です。

int x = 2;
{
   int y = 2;
   while (y > 0)
   {
      System.out.println(x + " "+ y + " ");
      x++;
      y--; // or --y;
   }
}

このコードを読んでわかるように、forループの3番目のセクションでpost演算子またはpre-decrement演算子を使用するかどうかは関係ありません。

より一般的には、次の形式のforループです。

for (ForInit ; Expression ; ForUpdate)
    forLoopBody();

whileループとまったく同じです。

{
    ForInit;
    while (Expression) {
        forLoopBody();
        ForUpdate;
    }
}

forループはよりコンパクトで、したがってこのような一般的な慣用句を解析するのがより簡単です。


  • 私はこれが超古くあることを知っています、しかし私はちょうど彼らが「同等」ではないことを指摘したいと思いました。 forループの例では" y"が原因です。ループ外で宣言されているため、whileループの例ではスコープ外のままです。 - OhFiddleDiddle
  • @OhFiddleDiddleは、この2つが本当に同等になるように角かっこを追加しました。 - Paul Wagland

26

これらを視覚化するには、forループをwhileループに展開します。

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

に展開します。

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

インクリメント式の結果(インクリメントの前後の値)は同じステートメント内では使用されないため、ループカウンターに対してポストインクリメントを行うかプレインクリメントを行うかは関係ありません。


17

それがあなたの懸念であれば、パフォーマンスの面で違いはありません。次のような場合にのみ誤って使用される可能性があります(したがってエラーに敏感です)。つかいますそれの間に増分

検討してください:

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使用されている。


  • ただし、それらをどのように使用したかに違いはありません。++iまたはi++操作は単独で行われます。 - Powerlord
  • インクリメント後の演算子では、インクリメント後に古い値を使用できるようにしておく必要があります。だからあなたの2番目の例が成り立つ必要があります0、インクリメントi覚えている0文字列連結の場合 - Ben S
  • +1。 for-loopを通常の3行程度のコードと考えたことは、これまでにありませんでした。 - Roman

13

++ iとi ++は、int num = i ++やint num = ++ iなどの代入演算子、またはその他の式と組み合わせて使用すると効果があります。 上記のFORループでは、他の式と組み合わせて使用されていないため、増分条件のみが存在し、違いはありません。この場合、それはi = i + 1を意味するだけです。


  • 投票数13しかし、それは間違っています。ではないのみ代入演算子と一緒に使用する場合:常に式の結果が使用されます(例えば、算術比較やメソッドパラメータなど)。 - fortran
  • @fortran:質問では、FORループでのi ++と++ iの使用の違いについて質問しています。したがって、FORループの文脈では、両方とも同じ意味です。私の答えがこの文脈で間違っているなら、あなたはもう少し説明することができますか? - Sachin Shanbhag
  • for(int i = 0; i < 10; doSomething(i++))またはfor(i = -1; ++i < 10;)プレインクリメントまたはポストインクリメントで使用した場合、実際には違いがあります。つまり、アサーションは、完全にforループ(最初の文でコンテキストを指定していないことを確認するためにもう一度読む)が間違っています。 - fortran
  • @fortran:私の答えを編集しました、現在の質問の状況ではこれで問題ないでしょうか? - Sachin Shanbhag

6

このループはこれと同じですwhileループ:

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

だから、そう、それは同じでなければなりません。


  • またはwhile(i++ < 5) - Nobody
  • @ rmx:しかしそうではないwhile(++i < 5)それがポイントです - Progman
  • @Progman:しないでくださいwhile(i++ < 5){...}と同等であるwhile(i < 5){i += 1;...}ではなくfor - 同等while(i < 5){...;i += 1;}? - Alan Plum

5

その記述はそれだけであるからです。増分の順序は関係ありません。


4

これら2つのケースは、インクリメントステートメントの実行後にiの値が比較されるため、同等です。しかし、あなたがした場合

if (i++ < 3) 

if (++i < 3)

あなたは物事の順序を心配しなければならないでしょう。

そしてあなたがした場合

i = ++i + i++;

それならあなたはただナッツです。


3

あなたの例には何もないので使う前後の増分から返される値。ラッピングしてみてくださいSystem.out.println()の周辺++xそしてx++違いを見るために。


3

からfor loopに関するJava言語仕様の章

BasicForStatement:

    for ( ForInit ; Expression ; ForUpdate ) Statement

... ForUpdate部分が存在する場合、   式はで評価されます   左から右への順序。彼らの   もしあれば、値は破棄されます。...   ForUpdate部分が存在しない場合は、   何もしません。

(ハイライトは私のものです)。


3

'for(初期;比較;増分)'の '増分'項目では使用しないため、出力は同じです。結果声明のうち、それは副作用これは、この場合は 'i'を増分していますが、どちらの場合も同じです。


  • これを拡張することができれば、それは揺るがすでしょう。 - Wolfpack'08
  • @Fohsapそれは私にとっては明確かつ完全なようです。そのうちのどの部分がわかりませんでしたか。 - user207421

2

インクリメント引数が評価される前にチェックが行われます。 「インクリメント」操作は、たとえ冒頭で宣言されていても、ループの終わりで行われます。


2

この例を試してください:

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

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

これで何ができるのかを理解できるはずです。


1

の値がyで計算されますforステートメントとの値xは独自の行で計算されますが、System.out.printlnそれらは参照されるだけです。

中を減らした場合System.out.println違う結果になるでしょう。

System.out.println(y--);
System.out.println(--y);


1

ここにたくさんの良い答えがあります、しかしこれが助けになるなら:

y--と--yは、副作用のある式、または式の後に続く式として考えることができます。 y--はこのようなものです(これらの例を疑似アセンブリとして考えてください)。

decrement y
return y

そして--yはこれをします:

store y into t
decrement y
load t
return t

ループの例では、戻り値をどちらかの方法で破棄し、副作用のみに依存しています(ループチェックは、減少ステートメントが実行された後に行われます。減少によって返された値は受け取りません)。


1

あればforループは式の結果を使用しましたi++または++i何かのために、それは本当だろうが、それは事実ではない、それはその副作用があるという理由だけでそこにある。

だからあなたも置くことができる理由voidそこにあるメソッドは、数値式だけではありません。


0

インクリメントは独立したステートメントとして実行されます。そう

そして

そして

--y;

は互いに等価であり、両方とも等価です

y = y - 1;


0

これは、

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

これは、ループの2つの変形と同じ結果になりますが、--yy--これはあなたのプログラムを壊すでしょう。


0

それは好みの問題です。彼らは同じことをします。

Javaクラスのコードを見ると、ポストインクリメント付きのforループがあります。


  • 彼らは同じことをする式の結果を使用していない場合。 - Michael Myers
  • @マイヤーズ:あなたは正しいです。しかし、それを実行するコードを見たことはありません(もちろん、それを意味するものではありません)。それコードが存在しません)。 - Roman

0

あなたの場合、それは同じです、まったく違いはありません。


0

あなたが正しいです。この場合、違いがわかります。

for(int i = 0; i < 5; )
       {
            System.out.println("i is : " + ++i);           
       }


0

はいそれはそれを順次します。初期化、それから評価条件、そして真ならばボディを実行し、そしてインクリメントする。

接頭辞と接尾辞の違いは、Increment / Decrementを使ってAssignment操作を実行した場合にのみ顕著になります。


0

for "arguments"の各部分は別々のステートメントであるため、違いはありません。

そして興味深いことは、コンパイラーが単純な事後増分を事前増分で置き換えることを決めることができ、これがコードの事を変えることはないということです。


  • 私は、(スマート)コンパイラはポストインクリメントもプリインクリメントも選択せず、単に変数に1を加えるだけだと思います(i += 1結果はステートメントで使用されていないためです。 - Carlos Heuberger
  • 正確には、ByteCodeは次のようになります。iincそしてそれは置き換えられますi++++iそしてi += 1。私はただコンパイラが++ii++すべてのケースでステートメントから操作し、それをsimple iinc元の文の前後に配置します。 - Colin Hebert

0

彼らは同じように振舞いません。以下のコンストラクトi ++あるものよりわずかに遅いです++ i前者は、の古い値と新しい値の両方を返すことを含むからです。。一方、後者はの古い値のみを返します。

それから、おそらくコンパイラは少し魔法をかけ、分離されたものを変更します。i ++++ iパフォーマンス上の理由から、生のアルゴリズムの観点からは、厳密には同じではありません。


  • パフォーマンスの議論は、世界で有効ですか?forループケース?私の推測では、ほとんどのコンパイラは、i ++を++ iに変更するのに十分なほどインテリジェントであるということでしょう。 - Pin
  • 彼らはする振る舞う同じ。それらは(?)異なる性能特性を持つかもしれませんが、それらの振る舞いは同じです。 - bruceboughton
  • Pin:私や他の多くの人が答えで言うように、おそらくコンパイラはpostfixの代わりにprefixのインクリメントを入れ替えることができます。 - rewritten
  • コンパイラはそれを単純なものに変更します。INCバイトコード。i += 1。 - Carlos Heuberger

0

Stackoverflowにも同様の記事がたくさんあります。

しかし、それはあなたの質問がより一般的であるように思われます。なぜならそれはどの言語やコンパイラにも固有のものではないからです。上記の質問の大部分は特定の言語/コンパイラを扱います。

これが要約です。

  • C / C ++ / Java(おそらくC#も)と最新のコンパイラについて話しているとします。
    • もしi整数です(const intintなど):
      • それからコンパイラは基本的に置き換えますi++++iなぜなら、それらは意味的に同一であり、それゆえ出力を変更しないからです。これは、生成されたコード/バイトコードをチェックすることで確認できます(Javaの場合は、jclasslibバイトコードビューア
    • それ以外の場合
  • それ以外の場合
    • コンパイラはそれらが意味的に同一であることを保証することはできないので、すべての賭けはオフになっているので、最適化しようとはしません。

あなたがC + +で後置と前置演算子をオーバーライドするクラスを持っているのであれば(のようにstd::iterator)、この最適化が行われたとしても、めったに行われません。

要約すれば:

  • あなたが言うことを意味し、そしてあなたが意味することを言う。のインクリメント部分forループする場合は、ほとんどの場合プレフィックスバージョンが必要です(つまり、++i
  • コンパイラの切り替え++iそしてi++いつもできるわけではありませんが、可能であればあなたのためにやろうとします。


0

ループでは、最初の初期化、次に条件チェック、そして実行、そしてその増加/減少の後。そのため、前後の増分/減分はプログラムコードに影響しません。


0

i ++(ポストインクリメント)と++ i(インクリメント前)の比較@me: "どちらの場合も、式は評価され、結果は条件との照合に使用されます。プレインクリメントの場合はインクリメントポストインクリメントの場合、インクリメント式も変数をインクリメントしますが、前の値を返します結果として、プリインクリメントはインクリメントされた値と比較し、ポストインクリメントはその値と比較します。元の値、どちらの場合も、条件がチェックされたときに変数がインクリメントされています。」 - ダムマー


0

ポストインクリメント演算子とプリインクリメント演算子の間にはかなり混乱があります。これは、「Robert SedgewickとKevin Wayneによる第4版のアルゴリズム」の抜粋から容易に理解できます。

インクリメント/デクリメント演算子:i ++はi = i + 1と同じであり、値は   私は式で。同様に、i--はi = i - 1と同じです。   --iは、式の値が増分/の後に取得されることを除いて同じです。   前ではなく、減少します。

例えば

x = 0; 
post increment:
x++;
step 1: 
assign the old value (0) value of the x back to x.So, here is x = 0.
step 2:
after assigning the old value of the x, increase the value of x by 1. So,
x = 1 now;

when try to print somthing like:
System.out.print(x++);
the result is x : 0. Because only step one is executed which is assigning 
old value of the x back and then print it.

But when, we do operation like this: 
i++;
System.out.print(i);
the result is x: 1. which is because of executing Step one at first 
statement and then step two at the second statement before printing  the 
value.

pre increment:
++x;
step 1: 
increase the value of x by 1. So, x = 1 now;
step 2:
assign the increased value back to x.

when try to print something like:
System.out.print(++1)  
the result is x : 1. Because the value of the x is raised by 1 and then 
printed. So, both steps are performed before print x value. Similarly, 
executing 
++i;
system.out.print(i);
Both steps are executed at statement one. At second statement, just the 
value of "i" is printed.

リンクされた質問


関連する質問

最近の質問