第 2 章 Java 言語の基本的な文法 I 5
2.9 文字列の連結演算
前節の問題2.8.2の出力文System.out.println( "x=" + x + ", y=" + y + ", x+y=" + z );に、加算記号 +がいくつも出ていますが、これらは何を加えているのでしょう?実は、これらは加算ではありません。演算子+に は、もう一つ「文字列の連結」という役割があるのです。
文字列リテラルを連結する、例えば"和田" + "雅美" とすると、"和田雅美"なる文字列リテラルが作られます。ま た、文字列に数値を連結することもできます。例えば、"答えは、" + 10とすると、"答えは、10"なる文字列リテラ ルが作られます。演算子+は、演算子をはさむ2つの値が数値の時は加算演算を、2つの値のいずれかが文字列であ るときは文字列の連結演算を行うのです。
問題2.9.1. 次の出力文が、望むべき出力「10 + 20 の計算結果は、30」とならない理由を説明しなさい。そして、解 決法を述べなさい。
System.out.println( "10 + 20 の計算結果は、" + 10 + 20 );
問題2.9.2. double型変数xに1.5、int型変数yに2が代入されているとして、以下のようにコンソールに出力す
る出力文 (System.out.println)を書きなさい。
x = 1.5, y = 2
問題 2.9.3. コンソールに次のように表示するプログラムを完成させなさい。なお、int型変数aとbの値を変える と、表示も正しく変わるように書くこと。例えば、a=10, b=20 としたら、出力も自動的に 10 + 20 = 30と書かれ るように。
ソースコード2.12 AdditionValues2.java (2つの変数の和2) package section0209;
public class AdditionValues2 {
public static void main(String[] args) { int a = 12;
int b = 34;
System.out.println( /* この中身を完成させる */ );
} }
12 + 34 = 46
なお、bに負の数を設定すると、10 + -20 = -10などと不自然になるが、この後でif文を学習すれば、10 - 20 = -10 と出力する方法を考え付くことができるでしょう。
2.10 1を加えるという操作
int型変数 xに現在入っている値を 1増やしたい!そんな時、どのような命令を書いたら良いでしょう。
これは Javaで良く出てくる場面なのですが、次のような代入文で書きます。
x = x + 1;
これを数学の等式と見てはいけません(こんなの成立しませんから)。’=’は代入演算子でした。従って、これは代入文 ですから、右辺の計算結果を左辺に代入ですね。つまり、変数 xに現在入っている値に1加えた値を計算し、それを 再び変数 xに代入する。つまり、変数xの値が 1増えるわけです。ただ x + 1;と書いても1増えません。
問題 2.10.1. 変数xの値を2 増やしたり、2減らしたり、2 倍したり、2で割ったり、2 で割った余りにしたりす る代入文をそれぞれ書きなさい。
変数xの値を2 倍する処理は、x = x + x; でもOK ですね。同様に、変数xに変数yの値を加えなさい、とい
う場合はx = x + y; で良いわけです。かつての試験で、変数xとyの値をそれぞれ1ずつ増やしなさい!と書いた
ら、x,y = x,y + 1;なんて式を発明した先輩がいました。無茶です。これは、単純にx = x + 1; y = y + 1;と 代入文を 2つ書けば良かっただけ。
問題 2.10.2. 変数xの値を2乗、3乗する代入文をそれぞれ書きなさい。残念ながら、べき乗する演算子はJava に は無いので、単純に掛け算を繰り返す。ただし、この書き方で 100 乗する計算は事実上無理ですよね。ではどうする か?は後で。
2.10.1 複合代入演算子
変数xの現在の値に五則演算をほどこしてxに戻す、という操作も頻繁に出てくるので、上記の方法以外にも次の ような書き方が許されています。例えば、問題2.10.1 の代入文は以下のようにも書けます。
x += 2; x -= 2; x *= 2; x /= 2; x %= 2;
プログラミング言語ぽくなってきましたね。これらの記号 (五則演算子と等号の対) を複合代入演算子と言います。+ と= は離さずに書きます。例えば、x += 2;はx = x + 2; と同じ操作をしてくれます。間違って、x =+ 2; と答 案に書いた先輩がいましたが、これではx = +2;(2を代入しただけ)になってしまいますね。
問題 2.10.3. 変数xに変数yの値を加算、減算、乗算、除算、剰余算する複合代入文をそれぞれ書きなさい。
問題 2.10.4. 次のプログラムでコンソールに書かれる出力を書きなさい。(aの値は次々変化していきます) ソースコード2.13 CompoundAssignment.java (複合代入演算)
package section0210;
public class CompoundAssignment {
public static void main(String[] arge) { int a = 0;
a += 7;
System.out.println( "a = " + a );
a -= 2;
System.out.println( "a = " + a );
a *= 5;
System.out.println( "a = " + a );
a /= 3;
System.out.println( "a = " + a );
a %= 3;
System.out.println( "a = " + a );
} }
a /= 3の所で間違わないで下さいよ(int型同士の計算ですから)。
問題 2.10.5. 複合代入文を用いて、変数xの値を 2乗する式を書きなさい。
問題 2.10.6. 次のプログラムがエラーになる理由を述べなさい。
ソースコード2.14 ErrorSubst.java (複合代入でのエラー) package section0210;
public class ErrorSubst {
public static void main(String[] args) { int a;
a += 5;
System.out.println( "a = " + a );
} }
今回は、エラーになるプログラムです。このとき、Eclipseはエラーがあると思われる行の頭に「ランプに赤い×の アイコン( )」を表示します。これが点灯すると、コンパイルエラーなので、実行できません。ポインタを赤い×の アイコンの上に持っていくと「ローカル変数aが初期化されていない可能性があります」との表示。おっしゃる通りで すね。では、アイコンをクリックして下さい。そして 3つほど解決策を提示してきますので、最初の「変数を初期化し ます」を選択しましょう。
変数は宣言しただけでは、値が未決の状態です。そんな変数に5を加えろと言っても、無茶ですね。int a = 0;の ように、初期値を代入しておいてからなら、5を加えることは可能です。(Javaはこういったところが融通が利きませ ん、というか、厳密でよろしい!というのかな)
2.10.2 インクリメント・デクリメント演算子
さらに、特殊な場合:加算で変化量が±1、つまり、ある変数の値を1 増やすか1減らすという場合には、3つめの 書き方ができます。
• 変数xに1加える場合、x++;もしくは ++x;
• 変数xから1減じる場合、x--;もしくは --x;
++も--も演算子です。変数名と演算子++は離してx ++;と書いても動きますが、慣例的に、変数に付けて書きま す。これらは単項演算子(1つの項に作用する演算子)で、++をインクリメント演算子(increment operator symbol)、 -- をデクリメント演算子(decrement operator symbol) と呼びます。この演算子の面白いところは、代入演算子 = を使わずに単独(例えば、x++;)で変数xの値を1 増やせるところです。(つまり、x = x++; ではなく、単にx++;
で1増える)
余談:C++というプログラミング言語を知っていますか。1983年にアメリカのベル研究所でC 言語の拡張として作 られた言語ですが、その名前の由来は、C 言語に対して一歩先を行く!という意味だとか(インクリメントなんです ね)。そして、C# という言語も知っていますか?こちらはマイクロソフト社がC++のまた一歩先を行く!ということ で付けた、らしいです(++を縦に2つ並べると#)。
問題 2.10.7. 変数xの値を1 増やす文を4種類を書きなさい。 (ヒント:インクリメント方式は2種類ありますね)
また先輩の珍解答を紹介!「変数xの値を2増やす方法を2通りで書きなさい」に対して、彼の解答は「x = x + 2;
と x++++;」これ無茶です!x++はx = x + 1に同等なので、x++++; は(x = x + 1)++;代入文のインクリメン トというのは定義から外れます。この場合の正解は、x = x + 2; とx += 2;ですね。また、「変数 xとyの和に1 加えた値を変数zに代入する式」をz = (x + y)++;と書くのも無茶です。無理やり書き換えると、(x + y)++は、
(x + y) = (x + y) + 1 となるので、これも無理。正解は、z = x + y + 1;ですね (無駄に難しく考えてはいけ ない)。
ところで、インクリメントもデクリメントも2種類ずつ用意されていますが、違いがあるのでしょうか?
++xのように前に演算子を付ける場合を「前置型」、x++のように後ろに演算子を付ける場合を「後置型」と呼びます。
まず、単独で使う場合には2 つに違いはありません。++x;とx++;のいずれも変数xの値を 1増加させるだけです。
違いが出てくるのは、これらを式の中で使う場合です。つまり、int y = ++x + 3;とかint y = x++ + 3;なんて 使い方です。えっ!こんな式変でしょ!?これまでの流れだと、int y = ++x + 3;はint y = (x = x + 1) + 3;
と解釈されるわけだから、式の中に代入文が入ってしまってエラーだよ!って?
いいえ、この解釈は間違っていません。式の中に代入文があってもエラーにはならないのです。実は、代入文
x = x + 1自体が値を持っているのです。代入文の値とは、その左辺の値となります。つまり、この場合 1を加えた
あとの変数 xの値ですね。よって、それにさらに3 を加えた値を変数yに代入するわけで、これはエラーではない。
試しに、以下のプログラムを動かしてみましょう。
ソースコード2.15 SubstInEquation.java (代入文は値を持つ) package section0210;
public class SubstInEquation {
public static void main(String[] args) {
int x = 10;
int y = ( x = x + 1 ) + 3;
System.out.println( "x = " + x );
System.out.println( "y = " + y );
} }
では、このプログラムの( x = x + 1 )の小かっこの中身を同等なインクリメント2種類 ++xとx++に替えて動 かしてみて下さい。変数y の結果が違ってきますね。前置型インクリメント++xだと、x = x + 1の場合と同じです が、後置型インクリメントx++の場合、yの値が1 小さくなる。これは、インクリメント( 1加える)の処理を式の計 算の前にやるか、後にやるかの違いなのです。次のようになります。
• 前置型の場合(int y = (++x) + 3;):まず、x = x + 1;を処理し、その結果を用いてint y = x + 3;
よって、x=11, y=14となります
• 後置型の場合(int y = (x++) + 3;):まず、int y = x + 3; を処理し、その後でx = x + 1;
よって、x=11, y=13となります
このようにインクリメント演算らを式の中に埋め込むと式が難しくなってしまいます。(でも無いですか?)間違って 読まれるより、式を (++x; int y = x + 3;などと) 2つに分解したほうが良いかもしれません。
問題 2.10.8. 以下のプログラムの出力結果を書きなさい。
注意:こんなプログラムは読む人を混乱させるだけなので、みんなは書かないように。あくまで、問題です。
ソースコード2.16 SubstInEquation2.java (式中のインクリメントは混乱原因) package section0210;
public class SubstInEquation2 {
public static void main(String[] args) { int x = 1;
int y = ( ++x ) + ( x++ );
System.out.println( "x = " + x + ", y = " + y );
} }
2.10.3 多重代入文
前節で書いたように、代入文を式の中に使える!ということから派生して、Java では多重代入文 (multiple
assignment statement)が書けます。つまり、複数の変数に同じ値を代入したいときに、つぎのような書き方ができる
のです。
ソースコード2.17 MultipleSubst.java (多重代入文) package section0210;
public class MultipleSubst {
public static void main(String[] args) { int a;
int b;
int c;
c = b = a = 1;
System.out.println( "a=" + a + ", b=" + b + ", c=" + c );
} }
先ほどの「式の中の代入文」の考え方で、c = b = a = 1;は、まず右から順に代入文を読んでいき、aの値がまず1 に、次にb = (a = 1) からbも1に、そしてc = (b = 1) よりcも1になるというわけです。でも、このプログ ラムは、以下のプログラムと同じですね。(^^;)
ソースコード2.18 MultipleSubst2.java (多重代入文は使わなくても) package section0210;
public class MultipleSubst2 {
public static void main(String[] args) { int a = 1;
int b = 1;
int c = 1;
System.out.println( "a=" + a + ", b=" + b + ", c=" + c );
} }
なお、c = b*2 = a = 1;とか、c = b++ = a = 1;なんてのはできません。理由はわかるかな?
問題 2.10.9. 多重代入文に複合代入文演算子も使えます。以下のプログラムの出力結果を書きなさい。
ただし、このプログラムもあくまで問題用ですね。
ソースコード2.19 MultipleSubst3.java (複雑な多重代入文) package section0210;
public class MultipleSubst3 {
public static void main(String[] args) { int x = 2;
int y = 3;
int z = 4;
z += y *= x;
System.out.println( "x=" + x + ", y=" + y + ", z=" + z );
} }