Java if文の条件式で==ではなくて=使っているのにコンパイルエラーにならない
問題
Oracle Certified Java Programmer, Bronze SE 認定資格対策で
Javaの文法普段書かないから挙動分からないなっていう問題あったので解説します。
下記のTest1.javaをコンパイル・実行した結果はどうなるでしょうか?
シンプルながら間違えやすい問題だと思います。
class Test1 {
public static void main(String[] args) {
boolean b = true;
if (b = false)
System.out.println(b);
System.out.println(b);
}
}
解説
1つ目の落とし穴
まず、if文の条件式に比較演算子==ではなくて、代入演算子=が使われています。
なので、コンパイルエラーになるかと思いきや、実はエラーは発生しません。
なぜなら、if文の条件式がboolean型であれば代入演算子を使ってもよいからです。
if (b = false) // bにfalseを代入してfalseを返す
このようにすると、bはboolean型なので、if文の条件式もboolean型になります。
b = falseは代入演算子で、bにfalseを代入してfalseを返します。
2つ目の落とし穴
if文の条件式がfalseを返すから、if文中の命令文は何も実行されず、
何も出力しないように思われます。
しかし、ここでも注意すべき落とし穴があります。
よく見ると、if文に波括弧{}がありません。
では、コンパイルエラーになるかといえば、そうはなりません。
波括弧{}がない場合、if文は次の一行だけを実行します。
if (b = false)
System.out.println(b); // この行だけがif文に属す
System.out.println(b); // この行は常に実行される
そのため、最初のSystem.out.println(b)は実行されず、
次のSystem.out.println(b)は常に実行されます。
つまり、Test1.javaと以下のTest3.javaは同じ内容を記述したコードになります。
class Test3 {
public static void main(String[] args) {
boolean b = true;
if (b = false) {
System.out.println(b);
}
System.out.println(b);
}
}
結局、if文は実行されず、bが出力されます。
bは宣言された時にはtrueでしたが、bにはfalseが代入されたので、
問題の解答はfalseになります。
余談
整数の代入は許されるのか?
整数の代入は、boolean型ではないので、コンパイルエラーになります。
class Test2 {
public static void main(String[] args) {
int a = 1;
if (a = 2)
System.out.println(a);
System.out.println(a);
}
}
if文の条件式(a = 2)がint型になりますが、if文の条件式はboolean型でなければなりません。
コンパイラは、
incompatible types: int cannot be converted to boolean
というエラーメッセージを出します。
boolean型のif文の条件式に=はあまり使わない方がいいよって話
boolean型ならば代入演算子=を使えますが、
これは意図しない動作を引き起こす可能性があります。
なので代入演算子=ではなく、比較演算子==を使うべきです。
if (b == false) // bとfalseを比較して結果を返す
このようにすると、bの値を変えずに、比較できます。
ちなみに、以下のように書いても同じ意味です。
if (!b) // bとfalseを比較して結果を返す
むしろ、こちらの書き方の方が自然かもしれません。
参考文献
・https://coderanch.com/t/366734/java/assignment-operator-statement
・https://stackoverflow.com/questions/2393988/getting-confused-with-and-in-if-statement
・https://wiki.sei.cmu.edu/confluence/display/java/EXP51-J.+Do+not+perform+assignments+in+conditional+expressions
Discussion