0
0

More than 1 year has passed since last update.

eclipse警告"assignment to variable xxx has no effect"についての覚書き

Last updated at Posted at 2022-09-29

ええと、入門者向けテストにありがちなクイズだと思いますが、以下のJavaコードがあった時、aが増えないステートメントはA~Fのどれでしょうか。

public class IncTest {
	static int a;
	static int b;
	public static void main(String[] args) {
		a++;      //A
		a=a++;    //B
		a=(a+=1); //C
		a=a+1;    //D
		a=++a;    //E
		b=a++;    //F
		System.out.println(a);
		System.out.println(b);
	}
}

正解はBですね。Javaの仕様では、上記のうちBの文a=a++;のみ、aのインクリメントが意味を持ちません。後置インクリメントa++は代入操作の後に行われることになっていますが、代入先もaなので、インクリメント前の値でアサインが完了してしまい、文の判定としてはインクリメント前のaに戻される(もともとのaが残る)ことになります。上記の実行結果は以下。

5
4

ただですね、ちょっと似たコードをeclipseで書いたとき、その警告文で少し戸惑ったんですよ。eclipseバージョンは2022-6(4.24.0)です。下記キャプチャのように、"assignment to variable a has no effect"の警告が、意味のないはずの文B(a=a++;)ではなく、E(a=++a;)の文の方に出てきたからです。
eclipseWarning2.png
先に言っておくと、これは正しい仕様です。それでも、「え、no effectなのはE(a=++a;)ではなくてB(a=a++;)の方なのでは・・・」と気になって確認したので、メモとして記事を残しておきます。

まず、この警告メッセージ、「変数への代入(アサインメント)の効果が無い」と言っているのであって、その文(ステートメント)に効果が無いと言っているわけではありません。代入に意味があるか、それ無しで結果が同じかがポイントなわけです。Eのa=++a;は、++a;と同じように1増える。つまり「a=」は無意味なので警告が出る。逆に、Bのa=a++;は、a++;と同じではない。文は結果としてaを変えないが、代入にはインクリメントを無効化する効果がある。なので、Bは警告が出ないのが正しい。・・・いや、考えたらその通りなんですけどね。詳しい方は「当たり前だろ」と思ってるかもしれません。

いちおう、eclipseの気持ちを確認するために、以下のように書き換えてみました。

public class IncTest {
	static int a;
	static int b;
	static volatile int c;
	public int d;
	IncTest(int d) {
		a++;      //A
		a=a++;    //B
		a=(a+=1); //C
		a=a+1;    //D
		a=++a;    //E
		b=a++;    //F
		c=++c;    //G
		d=d;      //H
		this.d=d; //I
	}
}

eclipseの言いたいことは、volatile宣言した変数cを見ると、更に明確になります。上記のうち、G(c=++c;)はE(a=++a;)と同じ前置インクリメント後の代入なのに警告が出ません。代入操作(c=と書くこと)に、コンパイラにとってのキャッシュ制御上の意味がある(かもしれない)からです。「=」が無駄なら警告が出るし、何らかのエフェクトがあれば出ないという基準が再確認できます。なお、このvolatile宣言時の規定については、2010年頃にeclipse仕様が修正される前の掲示板のやりとり(BUG 310264)を確認することができました。

また、上記コード、mainメソッドではなく引数:int dのコンストラクタに書き換えているのですが、H(d=d;)とI(this.d=d;)についてはどうでしょうか。当然のように、Hには警告が出てくれました。恐らくですが、この警告のメインターゲットは、このthis.d=d;をd=d;と誤って書いてしまうケースなのではないでしょうか。割と起こりえるミスなので、やはり、この警告の存在自体は助かります。逆に、私が勝手に混乱していたB(a=a++;)とE(a=++a;)のようなコードは、冒頭のクイズ問題のような例外的ケースでしか書くことがないでしょう。

今回は、少し検索すれば出てくるような内容なので、ちょっとネタとしては微妙だったかもしれません。ただ、volatileの話と警告の意義(this抜け防止)を含めて書くと意味があるかもと思ったので・・・。以上、覚書きでした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0