Oracle Java SE11 Silver を合格したので勉強内容をお裾分け

はじめに

先日OracleのJava SE11認定試験(正確にはSE 11 Programmer I )を合格し、晴れてSilverの資格を得ることに成功しました。ちなみに見事一発合格です。イェイ。

何のことか分からない方のためにざっくり説明しますと、Javaというプログラミング言語があり、現在Oracle社(データベースで有名)がその仕様を決定・改良しているのですが、Javaの理解度を公的に示すものとしてOracle社が取り行っているのがこの認定試験です。
一言で言えば、公式のお墨付きを得るための試験ですね。

Javaは現在最も広く使われている言語であり、安全性の高さから大規模なシステムの開発に向いている言語です。最近の有名どころで言えばみずほ銀行の新規システム(IT業界のサクラダファミリアとも言われた日本史上最大規模の勘定系システム)がJavaで動いています。

そのためSEでJavaと関わらない人はごく少数で、Javaができ、かつJavaプロジェクトの経験年数が長いSEはほぼ食いっぱぐれません。よほど人柄に問題がなければまず何かしらの案件に入れます。自分が受験したのも、昨今の情勢下から経歴書の欄を少しでも賑やかにしたいと思ったためです。

試験の難易度

ここから先は専門用語も交えます。分からない方はごめんなさい。

勉強し、受けた感想を一言で表せば「重箱の隅をつつくような試験」です。

基本中の基本である変数についても、関わる単語がとにかく多い。
プリミティブ型、参照型、ラッパークラス、フィールド、ローカル変数、配列、リテラル、etc...と、単語だけでも多い上、位置によってカテゴリが変わったりもするのでややこしい。

加えて度重なるアップデートを経ているため、Java8と比べてもJava11ができることはとても多くなっている。参考にした書籍によっては載っていないことも普通にあります。

自分は下記リンクにあるインプレス社発行のテキストで勉強しましたが、同じ会社が発行しているJavaの参考書は、対応しているのがJava8まででした。

ちなみに自分は、初めて一章を開いた時に思わず「うえぇ」と声が出ました。
読んでみれば分かりますが、とにかく意地の悪い問題が多い。絶対に開発現場でしないような書き方のコードも出してきているので、一周目は3分の1しか分からず、一通り問題をこなした後に実践問題に挑んでも正答率は半分以下でした。

本番合格ラインは正答率63%。当然この時点では不合格です。しかしひと月みっちり勉強したことにより、何とか正答率80%後半で試験をクリアできました。

試験を受けてみて思ったこと

先ほど問題の意地が悪いと書きましたが、そうした問題を通ることで将来的に起こりうる大事故を防ぐことができるのだろう、とも思いました。

というのもプログラミング言語は大体のルールやメソッドは違う言語でも同じものが多いため、ひとつ学んでしまえば二つ目以降の言語を学ぶ労力はグッと少なくなるのです。メジャー中のメジャーであるJavaはその典型とも言えるでしょう。

しかしそれが落とし穴となって些細な違いを見落とす可能性は少なくないでしょう。エラーが出ても前に勉強した言語を基準にJavaのコードを見てしまうと気付けるものも気付けなくなる。実際自分も、勉強の初めの頃はそれが原因で何度も答えを外しました。

そんな自分が合格ラインを大きく上回って合格できたのは、発見した穴を一個一個確実に潰していったからです。特別なことは何もしていません。
具体的には、テキストの一周目で分かっていない部分を洗い出し、二周目で理解したつもりだけれどまだ甘かった部分を埋めて行き、その後は二回間違ったところを見直したり各種APIを勉強したりしました。
大雑把に壁を作る(1周目)→総浚いして穴を見つけて塞ぐ(2周目)→補修の流れですね。

そんな中から個人的に特に理解に時間がかかった点、間違えやすかったポイントを下記にご紹介します。受ける予定のある方、今後受けるかも知れない方の一助となれば幸いです。

1.変数

public class Sample {
	int x;
	String s1;
	public void test() {
		int y;
		String s2;
		System.out.println(x);    //code1
        System.out.println(s1);   //code2
        System.out.println(y);    //code3
        System.out.println(s2);   //code4
	}
}

上に挙げたSampleクラスのコードですが、エラーとなるものがcode1~4の中で2箇所あります。

それはcode3と4です。これは変数の宣言箇所の問題で、クラス内で宣言された変数(フィールド)はクラスの生成(ロード)時に自動で初期化されているのに対し、メソッド内で宣言されている変数(ローカル変数)は明示的に初期化や代入をしなければ値が入ることはありません。これはエントリーポイント(public static void main(String args[]))も同様なのでご注意ください。
フィールドに初期化時に入る値は変数の型によって異なり、int型は0、String(参照型)にはnull(参照なし)が入ります。

ちなみにここも勘違いしやすいのですが、String型などのいわゆる参照型変数(値そのものではなく、値が格納されているアドレスが入っている変数)にnullが入っている場合、それはどこのアドレスも参照していないということを示しているのであって、決して空白("")ではありません。
そのためnullが入った参照型変数を画面出力(上記で言えばcode2)すると、画面にはそのまま「null」が表示されます。エラーにはなりません。

2.switch文

public class Sample2 {
	String s;
	public void test() {
		int x = 1;
		switch(x) {
		case 3 :
			s += "1";
			break;
		default :
			s += "1";
		case 1 :
			s += "1";
		case 10 :
			s += "1";
			break;
		}
		System.out.println(s);
	}
}

自分が思う中で序盤で一番引っかかりやすいのがこのswitchを問う問題です。
重要なポイントは1に条件式です。頭に入れておきたいのは以下の三点。

・使用できるのは①int型以下のプリミティブ型orそのラッパークラス(Integerとか)、②文字or文字列、③列挙型
・nullが入っている参照型変数だとエラーが発生する
・long、浮動小数点型(doubleやfloat)、真偽値(boolean)、またはこれらのラッパークラスは使用できない。

サンプルのコードで言えば、条件式に使用しているint型の変数xをlong型やdouble型に変更するとエラーになりますし、String型のフィールドであるs(クラス生成時にnullで初期化されている)を入れればNullPointerExceptionが発生してしまいます。

それを把握した上でSample2クラスのtestメソッドを実行してみましょう。画面には「null11」と表示されます。
String型にnullが入っていた場合、そこに文字列連結をするとnullの後ろに文字列が追加されていくのでこうなります。

そしてコード上ではcase句で指定された条件に合致しているのが1件しかないにも関わらず、付け加えられた"1"は2つあります。
この状況を引き起こすcase句の仕組みが以下になります。

・条件式の条件に当てはまるcaseを最初に全て確認した後、当てはまるcaseから順に下へと処理を続けていく。
・処理の後にbreak文を置かなければ次のcaseの処理も実行、break文が現れるまで処理を続ける。
・default文は最初の確認時に当てはまるcaseがない場合に処理実行し、break文に出会うまで処理を行う。

つまりtestメソッドの処理の流れだと、
①case句で条件に合致するものを探索
②合致するcase(数値の1)を発見したので文字列連結実行
③breakがないので次の文字列連結(case 10の処理)も実行し、switch文を抜ける。
④変数s(中身はnull11)を画面出力。
という風になる訳です。

これとは別に個人的に引っかかったポイントがありまして、それが以下の二点。
・case句に定数宣言(=final修飾子付き)されていない変数は使用できない。
・defaultは最初の探索で当てはまるcaseを発見できなかった場合に入る。

この憎っくきswitch文に自分は何度も引っかかったので、皆さんもぜひご注意を。

ひとまずここまで書いてきて

ざっと書いてきましたが、まだまだ書くことがあるというのに、もうすでにかなりの長さ。この大変さを思えばテキストを作成した著者の方々には足を向けて寝られませんね。

記事的にもこれ以上長くなるとだれてくるので、また気が向いたら続きを書きたいと思います。

この記事が気に入ったらサポートをしてみませんか?