三項演算子で代入

yharaさんのblogを見て、少し気になるところがあった。

true ? 1 : x = 2

のようなソースがパースエラーにならないかどうか。
(略)

  • 書けない:

[prog] 三項演算s…もとい、条件演算子の右辺に代入が書けるかどうか

早速試してみる。

C:\Users\quabbin>copy con A.java
class A{ int i = (true ? 1 : int x = 2);}
^Z
        1 個のファイルをコピーしました。
C:\Users\quabbin>\Develop\Language\jdk1.6.0_07\bin\javac.exe A.java
A.java:1: '.class' がありません。
class A{ int i = (true ? 1 : int x = 2);}
                                 ^
A.java:1: ';' がありません。
class A{ int i = (true ? 1 : int x = 2);}
                                      ^
エラー 2 個

バージョンについては深い突込みをしないでください。
そのまま訳しただけでは…やはりダメですね。
だば、宣言を別にしてみたらどうでしょう。

C:\Users\quabbin>del A.java

C:\Users\quabbin>copy con A.java
class A{ int x; int i = (true ? 1 : x = 2);}
^Z
        1 個のファイルをコピーしました。

C:\Users\quabbin>\Develop\Language\jdk1.6.0_07\bin\javac.exe A.java
A.java:1: 予期しない型
期待値  : 変数
検出値  : 値
class A{ int x; int i = (true ? 1 : x = 2);}
                              ^
エラー 1 個

これでもダメだけど、少し解釈できているっぽい。

さて、ここで少し考えてみるとします。
三項演算子の後ろの二つは、何らかの値を返すことが期待されてますよね。
正確な理由は分からないが、Javaでは「if( i = 0 ){}」みたいなバグっぽいものを書けなくするためか、そういう場合は代入の記述が直接出来ないこととなっているようです。
しかし、Javaで記述する場合、条件判断を与える場所に代入を書かないとコードが冗長になる時もあります。
例えば、ファイルを文字列として行読み込みするときなんかがそれにあたりますが、当然簡潔に書く方法もあるわけです。

BufferedReader reader = null;
String line = null;
while(null != (line = reader.readLine())){
	// do something
}

変数lineに代入している部分が()で括られているところがキモ。
応用してみましょう。

C:\Users\quabbin>del A.java

C:\Users\quabbin>copy con A.java
class A{ int x; int i = (true ? 1 : (x = 2));}
^Z
        1 個のファイルをコピーしました。

C:\Users\quabbin>\Develop\Language\jdk1.6.0_07\bin\javac.exe A.java

C:\Users\quabbin>dir *.class
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 3574-3602 です

 C:\Users\quabbin のディレクトリ

2009/01/08  23:26               219 A.class
               1 個のファイル                 219 バイト
               0 個のディレクトリ  145,907,171,328 バイトの空き領域

というわけで、成功しました。

しかし、Javaもダークサイドが多いですね。