訳あってJava Silverの資格勉強をしているのだが、勉強していて
「これってこういうふうにしても動くんだ~」という発見や驚きがあったので
そういうのを忘れない為に書き留めていこうと思う。
・記事の対象者
①Javaの初学者
②Java Silverの資格勉強をしている人
①制御文(if、for、while等)の中括弧を省略しても動作する
Java Silverの勉強をしていて一番驚いたのがこれ!!
例えば以下のコードの場合でもエラーにならず動作する。
この場合はif文の次の1文がif文の条件に合致した時の処理として使われる。
if(i = 3)
System.out.println("処理1ですー。");
System.out.println("処理2ですー。");
上記のコードは、下記のコードの動きと同一になる。
if(i = 3) {
System.out.println("処理1ですー。");
}
System.out.println("処理2ですー。");
どちらを使っても動くには動くが、保守性や可読性等が下がるため、基本的には省略せず
例②のように {}を使用する事。
②数値型にアンダースコア(_)を入れてもエラーにならない場合がある
これも勉強していて驚いた事。アンダースコアを使った数値表記はJava SE7から導入されたらしく
下記のルールに従えば、場所や回数は自由らしい。
・先頭と末尾には記述不可
・記号の前後には記述不可
なので、例えば下記のようなコードはOKになる。
int a = 123_456_789;
int b = 1_____9;
しかし、下記のようなコードだとエラーになる。
int a = _123_456_789;
int b = 123_456_789_;
float b = 3_.1415;
基本数値型にアンダースコアを入れることは無いと思うが、覚えておいて損は無いと思う。
③変数宣言時、変数名によってはエラーになる場合がある
変数宣言をする際、基本的にはその変数の使用用途によって変数名をきめると思うが
その際、下記のような変数名だとエラーになる場合がある。
int $[a} = 100;
int b.c = 200;
変数名やメソッド名等の名前の事を 「識別子」 と呼ぶが、識別子の命名規則により
上記のような変数名だとエラーになる時がある。
命名規則としては主に下記のルールがある。
・予約語は使用できない
※予約語については下記参照
https://eng-entrance.com/java-reserved-word
・使える記号はアンダースコア(_)と通貨記号の2つ
・数字は2文字目からでないと使用できない。1文字めのみNG
なので、下記のような変数名だと使用できる。参考にしていただければ・・・。
int $a = 100;
int b_ = 200;
int _0 = 300;
④インターフェースのデフォルトメソッドについて
Java SE8からインターフェースに使えるようになったメソッド。
Java SE7までは、インターフェ∸スに「抽象メソッド」という具体的な処理を記述しない
メソッドのみ使用できた。
interface testInterface{
abstract public void testMethod();
}
Java SE8からは「default」というキーワードを記述することによって
インターフェースに具体的なメソッドが記述できるようになった。
interface testInterface{
//default句を使うことで、interface内にメソッドを実装できる。
default String testName(){
return "名前";
}
}
public class testSample implements testInterface{
}
public class testClass{
public static void main(String[] args) {
testInterface sample = new testSample ();
// 結果:「名前」が表示される。
System.out.println(sample.testName());
}
}
defaultが使えることによって、実装するクラス内でオーバーライドして
メソッドの処理内容を記述する必要がなくなるというメリットがあるように思う。
⑤インターフェースの多重実現について
Javaで2つ以上のクラスを同時に継承する多重継承はダメだが
インターフェースの多重実装は可能。その際注意がいるのが
メソッド名、引数の型、引数の数が全て同じのデフォルトメソッドの存在になる。
全て同じのデフォルトメソッドを持つインターフェースを多重に実現した場合
どちらのデフォルトメソッドの実装を使うのかの宣言がいる。宣言が無いとエラーになる。
具体的には、下記のようにデフォルトメソッドをオーバーライドし
その処理内でどちらかのデフォルトメソッドを呼び出せばエラーにならない。
interface testInterfaceA{
default void test(){
System.out.println("A");
}
}
interface testInterfaceB{
// testInterfaceAと同じメソッドを実装
default void test(){
System.out.println("B");
}
}
public class Main implements testInterfaceA, testInterfaceB{
public static void main(String[] args) {
System.out.println("C");
}
@Override
public void test() {
testInterfaceA.super.test();
}
}
⑥ラムダ式について
Java SE8から新たに導入されたもの。ラムダ式の特徴でありメリットしては
メソッドを変数のように扱える、という点にある。
書き方としては基本的に下記になる。
(引数) -> {処理};
(String name) -> {System.out.println(name);};
注意点としては、ラムダ式で変数した変数以外は使えない、という点がある。
なので、下記のようなコードはコンパイルエラーになる。
// 変数名が一致していない
(String name) -> {System.out.println(value);};
また、ラムダ式は下記のようにかっこを省略することが可能。
// 括弧を省略
String name -> {System.out.println(value);};
ただし、かっこを省略できるのは引数が1つの時だけで、2つ以上の引数を受け取るメソッドでは
省略できない。
ラムダ式では引数のデータ型やかっこが省略できるが、実行したい処理が1つしかない場合は
下記のように中かっこ「{}」も省略できる
interface testInterfaceA{
void test(int A)
}
public class Sample{
public static void main(String[] args) {
Test t = (x) -> System.out.println(x);
t.test(10);
}
}
中かっこを省略した場合、下記のように2つ以上の処理を記述する事はできない。
public class Sample{
public static void main(String[] args) {
// コンパイルエラーになる。
Test t = (x) -> System.out.println(x); System.out.println(x);
t.test(10);
}
}
⑦ラムダ式からアクセスできる範囲について
ラムダ式は、それを囲むブロックと同じスコープを持つ。
なので、ラムダ式から囲むメソッドのローカルにアクセスする事もできる。
下記のコードだと、mainメソッド内で宣言したローカル変数testをラムダ式内でコンソール出力している。
interface Function {
void test();
}
public class Main {
public static void main(String[] args) {
String test = "hello worldだよー。";
Function f = () -> {
// コンソール出力しているコード。
System.out.println(test);
};
f.test();
}
}
ただし、finalなローカル変数として扱える変数だけにアクセスできるというルールがあるので
注意が必要。具体的に言うと、finalで修飾されていなくても変更されない変数という意味になる。
例えば、下記のコードのようにラムダ式内でローカル変数の値を変更するとコンパイルエラーになる。
public class Main {
public static void main(String[] args) {
String test = "hello worldだよー。";
Function f = () -> {
// エラーが発生するコード。
test = "test";
System.out.println(test);
};
f.test();
}
}
⑧関数型インターフェイスについて
関数型インターフェイスはプログラマーが自由に使えるが、頻繁に使われるものは
Java SE8で標準クラスライブラリにjava.util.functionパッケージとして追加される。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/package-summary.html
試験で良く出題されるであろうインターフェイスは下記4つだと思われるので
覚えておいて損は無いだろう。
関数型インターフェイス | 説明 |
---|---|
Cousumer | 引数を受け取って処理をする。結果は戻さない。 |
Supplier | 何も受け取らず結果だけを戻す。 |
Predicate | 引数を受け取ってboolean型を返す |
Function | 引数を受け取って、指定された型の結果を戻す。 |
⑧Mathクラスについて
Java.lang.Mathは、数値の累乗や平方根といった数値処理をするためのクラス。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Math.html
試験で良く出題されるであろうMathクラスのメソッドは下記2つだと思われる。
①powメソッド pow(double a, double b)
引数2つ。1番目の引数を、2番目の引数で累乗した値を返す。
②sqrtメソッド sqrt(double a)
引数1つ。double値の正しく丸めた正の平方根を返す。
⑧Comparatorインターフェイスについて
Java.util.Comparatorインターフェイスは、コレクション内のオブジェクトを並び順を決める
アルゴリズムを定義するもの。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Comparator.html
⑨Characterクラスのメソッドについて
int型に対するIntegerクラスやdouble型に対するDoubleクラス、boolean型に対する
Booleanクラスのように、プリミティブ型に対応したクラスの事を ラッパークラス と呼ぶ。
Characterクラスはchar型のラッパークラスで、char型の値を扱うためのメソッドを数多く持っている。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Character.html#:~:text=Character%20%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AF%E3%80%81%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96%E5%9E%8B,%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82
代表的なメソッドは下記。
メソッド名 | 説明 |
---|---|
isAlphabetic | 引数で受け取った文字がアルファベットかどうかを調べる |
isDigit | 引数で受け取った文字が数字かどうかを調べる |
isLowerCase | 引数で受け取った文字が小文字かどうかを調べる |
Function | 引数を受け取って、指定された型の結果を戻す。 |
⑩LocalDateクラスのメソッドについて
JavaSE8からLocalDateというDateクラスやCalendarクラスを改良したクラスが追加された。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html
特徴としては主に下記2つがある。
・Calendarクラスでは月が0から始まったが、LocalDateでは1から始まりより扱いやすくなり
間違いが少なくなった
・日付を操作するための便利な下記のようなメソッドが追加された。
メソッド名 | 説明 |
---|---|
of | 年、月、および日からLocalDateのインスタンスを取得する |
now | 指定されたタイムゾーンから現在の日付を取得する |
parse | 2021-05-16などの文字列からLocalDateのインスタンスを取得する |
⑪temporalAdjustersについて
時間的なオブジェクトを変更するための主要なツールにtemporalAdjustersというインターフェースです。
例として、週末を避けて日付を設定する機能や、日付を月の最後の日に設定する機能などがある。
※下記URL参照
https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAdjusters.html
⑫ArrayListについて
Javaでは何らからの集合のことを 「コレクション」 と呼ぶ。配列はコレクションを扱うクラスの1つですが
次のようないくつかの制約がある。
・扱える要素数は最初に決める必要あり
・要素アクセスには添字を使わなければいけない
・要素アクセスの際には、要素数を超えないよう配慮しなければならない
Javaにはもっと簡単にコレクションを扱える「コレクションAPI」と呼ばれる複数の
インターフェースやクラスで構成されるクラス群がある。
このコレクションAPIのうちのひとつがArrayListである。ArrayListは 「動的配列」 とも呼ばれ
配列のように使えることが特徴。※詳細な特徴は下記参照
https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayList.html
ArrayListの特徴は次の通り
・必要に応じて要素数を自動的に増やす
・追加した順に並ぶ
・nullも値として追加できる
・重複した値も追加できる
具体的な使い方は下記の通り
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("テスト1");
list.add("");
list.add("テスト1");
// テスト1, , テスト1と表示される
System.out.println(list.toString());
}
}
⑬ジェネリクスについて
Java SE 5からジェネリクスが導入された。ジェネリクスは、型を指定することで
扱える型を制御する機能。
※下記URL参照
https://www.sejuku.net/blog/22699
例えば次のコードはStringしか扱えないArrayListを作っている
ArrayList<String> list = new ArrayList<String>();
なお、上記のように指定している型の事を「型パラメータ」と呼ぶ。
ジェネリクスを使用しない場合、ArrayListのようにString型、Integer等の方が混在する
配列を扱う場合、下記のコードのようだとエラーが発生する。
public class Main {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add(new Object());
list.add("test");
list.add(new Integer(10));
for (int i = 0; i < list.size(); i++) {
// ClassCastExceptionが発生する
String str = (String) list.get(i);
}
}
}
⑭ArrayListのaddメソッドについて
ArrayListに要素を追加するにはaddメソッドを使用する。addメソッドは引数で渡された要素を
後ろに追加するメソッド。addメソッドは追加する場所を下記のように設定することもできる。
list.add(2, "B");
上記は文字列「B」を「2番目」に追加するという意味。具体的な使い方は下記の通り。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add(0, "B");
list.add("C");
list.add("D");
for (String str : list) {
// 「BACD」と表示される
System.out.print(str);
}
}
}
ただし下記のように存在しないリストの番号に追加しようとすると、文法上誤りではなく
コンパイルエラーは発生しないが、実行すると「IndexOutOfBoundsException」が発生する。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add(2, "B");
list.add("C");
list.add("D");
for (String str : list) {
// 「IndexOutOfBoundsExceptionが発生する
System.out.print(str);
}
}
}
⑮ArrayListのsetメソッドについて
上記で記載したaddメソッドは要素を追加するメソッドだが、要素を置換するためのメソッドとして
setメソッドというものがある。※下記参照
https://www.sejuku.net/blog/20140
setメソッドは元の要素を上書きすることに注意が必要。具体的な使い方は下記の通り。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.set(0, "B");
list.add("C");
list.set(1, "D");
for (String str : list) {
// BDと表示される
System.out.print(str);
}
}
}
⑯ArrayListのremoveメソッドについて
上記で記載したsetメソッドは要素を置き換えるメソッドだが、要素を削除するメソッドとして
removeメソッドというものがある。 ※下記URL参照
https://www.sejuku.net/blog/14802
例えば下記のようなコードを実行すると、「ABC」と表示される。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.remove("D");
for (String str : list) {
// ABCと表示される
System.out.print(str);
}
}
}
removeメソッドの注意点として、値を削除する際、後ろの要素が繰り上がる仕組みになっている。
例えば、下記のようなコードを実行すると、「AC」ではなく、「A」と表示される。
この辺り間違えやすい要素なので覚えておきたい。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (String str : list) {
if ("B".equals(str)) {
list.remove(str);
} else {
// Aのみ表示される
System.out.print(str);
}
}
}
}
⑰ArrayListへのアクセスについて
Javaで2つの処理を同時にする際、片方の処理がArrayListから値を読み出している最中に
もう片方の処理が同じArrayListのインスタンスから要素を削除しようとすると、下記のような
ConcurrentModificationException が発生する。
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at com.example.daily_report.Main.main(Main.java:19)
例えば、下記ソースのように拡張for文で要素を取り出し、removeメソッドで要素を削除した後に
再度拡張for文で要素を取り出すとConcurrentModificationExceptionが発生する。
複数の処理で同じArrayListを呼び出すときは、 要素を削除したり移動させてはいけない。
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
for (String str : list) {
if ("C".equals(str)) {
list.remove(str);
}
}
// ConcurrentModificationExceptionが発生する。
for (String str : list) {
System.out.print(str);
}
}
}
⑱固定長のリストについて
Listの代表の1つとしてArrayListがあると思うが、ArrayListは「動的配列」とも呼ばれ
addメソッド等で要素数を動的に増やすことができる。
反対に固定長のリストを作るには下記の方法がある。
・ArraysクラスのasListメソッドを使い、配列からリストのインスタンスを作成
・Listインターフェースのofメソッドを使いインスタンスを作成
1つ目のArraysクラスというクラスを使えば、配列からのリストのインスタンスを作成する事ができる。
しかし、作成したリストは固定長の為、下記のようにaddメソッド等で要素を追加しようとすると
実行時にjava.lang.UnsupportedOperationExceptionというエラーが発生してしまう。
String[] words = { "abc", "def", "ghi" };
List<String> list = Arrays.asList(words);
// java.lang.UnsupportedOperationExceptionが発生。
list.add("abc");
2つ目のListインターフェースのofメソッドを使う場合も固定長のリストを作成する。
固定長の為、1つ目と同様、下記のようにaddメソッド等で要素を追加しようとすると
実行時にjava.lang.UnsupportedOperationExceptionというエラーが発生してしまう。
List list = List.of(1, 2, 3);
// java.lang.UnsupportedOperationExceptionが発生。
list.add(4);
⑲mismatchメソッドについて
mismatchメソッドとは、Arraysという配列を扱うためのクラスで提供する為のメソッドの一つ。
引数で渡された2つの配列の要素を先頭から順番に比較し
一致しない要素の添字(インデックス)と戻す。
※詳しくは下記URL参照
https://dimzakki.com/java-mismatch-method/
例えば下記のコードの場合、aとbの2つの配列で最初の要素が一致していない。
その為、1番目の要素を表す添字「0」が表示される。
public static void main(String[] args) {
String[] a = { "b", "c" };
String[] b = { "a", "b", "c" };
// 0が表示される。
System.out.println(Arrays.mismatch(a, b));
}
また下記のコードの場合、aとbの2つの配列で全ての要素が一致する場合は
「-1」が表示される。
public static void main(String[] args) {
String[] a = { "a","b", "c" };
String[] b = { "a", "b", "c" };
// -1が表示される。
System.out.println(Arrays.mismatch(a, b));
}
⑳compareメソッドについて
compareメソッドは、上記mismatchメソッドと同様、Arraysという配列を扱うためのクラスで
提供する為のメソッドの一つ。2つの配列を辞書順に並べたときの並び順を比較する。
2つの配列が等しいかどうかを確認するequalsメソッドと間違いやすいので注意が必要。
※詳しくは下記URL参照
https://programmer-life.work/java/array-compare
compareメソッドは、引数で受け取った2つの配列が等しい場合は0を戻し
第一引数が第二引数よりも辞書順で先なら負の値を、逆に第二引数のほうが先なら正の値を戻す。
例えば下記のコードの場合、1つ目の配列の最初の要素「B」は比較対処の2つ目の配列の
最初の要素「A」よりも辞書順では後ろにいる。そのため、正の値が戻される。
public static void main(String[] args) {
String[] a = { "B", "A" };
String[] b = { "A", "B" };
// 1が表示される。
System.out.println(Arrays.compare(a, b));
}
㉑removeifメソッドについて
removeifメソッドは、Listインターフェースのスーパーインターフェースである
Collectionインターフェースが持つメソッドで。removeifメソッドは引数で渡されたラムダ式が
trueを戻せば、コレクション内の要素を削除するように実装されている デフォルトメソッドの1つ。
※詳しくは下記参照
https://codechacha.com/ja/java-collections-arraylist-removeif/
下記のソースだと、引数sの文字列が「B」のときにtrueを戻すラムダ式が与えられているので
「A、C」が表示される。
public static void main(String[] args) {
List<String> list = new ArrayList<>(
Arrays.asList(new String[] { "A", "B", "C" }));
list.removeIf(
(String s) -> {
return s.equals("B");
});
// A、Cと表示される。
System.out.println(list);
}
㉒forEachメソッドについて
拡張for文と似たものとしてforEachメソッドというものがある。
※詳細な内容は下記参照
https://camp.trainocate.co.jp/magazine/java-foreach/
複雑な処理をする場合には拡張for文を使うが、簡単な繰り返し処理の場合は
forEachメソッドを使用する。
例えば下記のソースのようにリストの要素を順番に表示するなどの簡単な処理を行う場合は
forEachメソッドを使用したほうがいい。
public static void main(String[] args) {
List<String> list = List.of("A", "B", "C");
// A、B、Cと表示される。
list.forEach(str -> System.out.println(str));
}
㉓Mapについて
Mapは、キーでオブジェクトを管理するデータ構造。リストが番号でオブジェクトを管理するのに
対して、Mapは名前とキーとしてオブジェクトを管理するのが特徴。
※詳細な内容は下記参照
https://www.bold.ne.jp/engineer-club/java-map
キーと値のセットを作るのがputメソッド。putメソッドの第一引数にキーを私
第二引数にバリューを渡す。
Mapの特徴として、値の重複は許容し、キーの重複は許容しないというところにある。
例えば下記のソースでは、putメソッドを5回使用しているが、キー「1」が重複しているため
System.outだと「4」と表示される。
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(1, "A");
map.put(null, "default");
// 4が表示される
System.out.println(map.size());
}
㉔try-catchについて
try-catchとは例外が発生する可能性がある処理を記載する時に使用する。
ここでいう例外とは、プログラム実行中に発生する何らかのトラブルを指す。
トラブルは、プログラマーの不注意で発生するバグや、要件や仕様の違い等
その種類は多岐に渡る。
※詳細な内容は下記参照
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/try...catch
構文としては下記になります。
try {
// 例外が発生する可能性がある処理
} catch (例外クラス型 変数) {
// 例外が発生した時の処理
}
例えば下記のコードでは、要素数0の配列を作り、存在しない1番目の要素として
値を代入しようとする。
その為、要素外のアクセスを示すエラーArrayIndexOutOfBoundsExceptionが発生し
すぐに対応するcatchに移動し「error」と表示され、「finish」と表示される事はない。
public static void main(String[] args) {
// errorと表示される
try {
int[] array = {};
array[0] = 10;
System.out.println("finish");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("error");
}
}
㉔try-catch-finallyについて
㉓で説明したように、tryで例外が発生すると、すぐcatchに制御が移る。その為、もし例外が発生すると
それ以降のtryは実行される事はない。
しかし、ネットワークの切断、開いたままになっているファイルのクローズなど
例外発生の有無にかかわらず実行しなければならない処理が存在する。
こうした例外発生の有無にかかわらず実行したい処理を記述したい時に使用するfinallyになる。
※詳しくは下記URL参照
https://www.javadrive.jp/start/exception/index3.html
例えば下記のコードでは、try内にあるSystem.outが実行され、その後finally内にある
System.outが実行されるので、「AC」と表示される。
public static void main(String[] args) {
//「AC」と表示される
try {
System.out.println("A");
} catch (NullPointerException e) {
System.out.println("B");
} finally {
System.out.println("C");
}
}
注意点として、try-catch-finallyの構文は、その出現順を変更する事はできない。
なので、下記のコードのようにtry-finally-catchのように順番を変更すると
コンパイルエラーが発生する。
public static void main(String[] args) {
//コンパイルエラーになる
try {
System.out.println("A");
} finally (NullPointerException e) {
System.out.println("B");
} catch {
System.out.println("C");
}
}
また、finallyは仮にcatch内でreturnされていてもfinally内の処理が実行される。
なので、例えば下記のコードのようにcatch内にあるreturnによってmainメソッドに戻ろうとした場合
finally内の処理を実行してからmainメソッドに戻るので「BA」と表示される。
public class Main {
public static void main(String[] args) {
System.out.println(test("A"));
}
private static String test(Object obj) {
// 「BA」と表示される
try {
System.out.println(obj.toString());
} catch (NullPointerException e) {
return "A";
} finally {
System.out.println("B");
}
return "C";
}
}
また、catchとfinallyの両方がretuenで値を戻す場合、必ずfinallyのretuenが返される。
例えば、下記のコードのようにcatchとfinallyの両方がretuenがある場合
finallyのruturnが最後に返され、「20」が返される。
public class Main {
public static void main(String[] args) {
int result = sample();
System.out.print(result);
}
private static int sample() {
// 20が返される
try {
throw new RuntimeException();
} catch (RuntimeErrorException e) {
return 10;
} finally {
return 20;
}
}
}
ただし、戻り値のための変数と、メソッド内で使われている変数は異なる点に注意がいる。
例えば下記のコードのようにfinallyで値を変更したとしても、変数の値が変わるだけで
戻り値が変わらないので「10」が返される。
public class Main {
public static void main(String[] args) {
int result = sample();
System.out.print(result);
}
private static int sample() {
// 10が返される
int val = 0;
try {
String[] array = { "A", "B", "C" };
System.out.println(array[3]);
} catch (RuntimeException e) {
val = 10;
return val;
} finally {
val += 10;
}
return val;
}
}
また、tryとfinallyは1つしか記載できず、catchのみ複数記載できるというルールがある。
なので、下記のコードのようにfinallyが2つ以上あると必ずエラーが発生するので注意が必要。
public class Main {
private static void main(String[] args) {
// コンパイルエラーが発生する
try {
System.out.println("A");
} finally {
System.out.println("B");
} finally {
System.out.println("C");
}
}
}
また、複数のtry-catchが入れ子になっている場合、例外が受け取るのはその例外に対応した
もっとも近いcatchになる。
例えば下記のコードのように、ArrayIndexOutOfBoundsExceptionが発生した場合
もっとも近いcatchがこの例外をキャッチする。このcatchが実行された後、finallyが必ず実行されるので
「DEG」が表示される
public class Main {
private static void main(String[] args) {
// DEGが表示される
try {
try {
String[] array = { "A", "B", "C" };
System.out.println(array[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("D");
} finally {
System.out.println("E");
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("F");
} finally {
System.out.println("G");
}
}
}
㉕try-with-resourcesについて
try-with-resourcesは、Java7から導入されたファイルなどの読み込み処理に
必ずclose処理が伴う処理に対して、確実にclose処理が実現できるtry-catch-finally構文の
代替となる構文の事。
※詳しくは下記のURL参照
https://gakumon.tech/java/java_try_with_resources.html
注意点として、tryで宣言した変数の有効範囲はtry内だけという点になる。
例えば下記のコードのように、finallyから参照することはできないので
確実にコンパイルエラーが発生する。
public class Main {
private static void main(String[] args) {
try (FileInputStream is = new FileInputStream("sample.txt")) {
throw new FileNotFoundException();
} catch (Exception e) {
System.out.println("A");
} finally {
// ここでコンパイルエラーになる
if (is != null) {
is.close();
}
System.out.println("B");
}
}
}
㉖エラーについて
エラーとは、プログラムからは回復不可能なトラブルが発生したことを指す。
例えば、実行マシンのメモリが不足したり、データが保存されているファイルに対する読み取りや
書き込みの権限がなかったりといった実行環境に関するトラブルはプログラムからは対処のしようがない。
エラーは例外処理をキャッチして処理することが可能。例えば下記のコードは強制的に
StackOverflowErrorを発生させているが、キャッチして例外処理を行っているため正常に終了する。
public class Main {
public static void main(String[] args) {
// StackOverflowErrorが発生する
try {
sample();
} catch (StackOverflowError e) {
System.out.println("A");
}
System.out.println("finish");
}
private static void sample() {
sample();
}
}
㉗例外エラーについて
Java Silverだと例外エラーが幾つか出題される。
※例外の種類については下記URL参照
https://docs.oracle.com/javame/config/cdc/ref-impl/cdc1.1.2/jsr218/ja/java/lang/class-use/Exception.html
例えば、下記のコードのように存在しない要素を取り出そうとするとIndexOutOfBoundsException
が発生する。
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// IndexOutOfBoundsExceptionが発生する
list.get(0);
}
}
このようなエラーを含め、下記のような例外エラーが出題される可能性があるので
覚えておく必要がある。
例外エラー | 説明 |
---|---|
IndexOutOfBoundsException | 存在しない要素を取り出そうとすると発生する |
ArrayIndexOutOfBoundsException | 配列の要素外にアクセスしようとすると発生する |
StringIndexOutOfBoundsException | 文字列の範囲外にアクセスしようとすると発生する |
㉘例外クラスについて
nullとは文字の一種で、変数が何も参照しないことを表現するためのデータ。
例えば下記のコードだと、nullになっている変数strがequalsメソッドで呼び出しているが
nullに対してメソッドを呼び出すようなコードを記述している。
このようなコードを記述するとNullPointerExceptionが発生する。
public class Main {
public static void main(String[] args) {
String str = null;
// NullPointerExceptionが発生する。
if (str.equals("")) {
System.out.println("blank");
} else {
System.out.println("null");
}
}
}
また、メソッドが呼び出されると、メソッドの実行に必要な情報がメモリのスタック領域に配置される。
次々とメソッドを呼び出せば、スタック領域にもメソッドの情報が積み重なっていく。
もちろん、スタック領域は無限ではなく、その広さは有限になっている。
その為、下記のコードのように同じメソッドを呼び出し続けるとスタック領域が足りなくなる。
そのことをJVMが検知するとStackOverflowErrorが発生してプログラムが終了します。
public class Main {
public static void main(String[] args) {
// StackOverflowErrorが発生する
main(args);
}
}
㉙Javaの修飾子について
Javaには修飾子というクラスやその変数が何処からアクセス可能であるかをしめすものがあります。
※詳しくは下記URL参照
https://java-code.jp/134
試験には主に下記のような修飾子が出るので覚えておいた方がいいでしょう。
修飾子 | 説明 |
---|---|
final | 値を変更できないものであることを表す |
static | クラス全体で共有されるクラス |
public | すべてのクラスからアクセス可能 |
protected | 同じパッケージ内あるいはサブクラスからのみアクセス可能 |
private | 同じクラス内からのみアクセス可能 |