Java好き

カテゴリ: 文法

型を変数のようにパラメータ化して、クライアント側が設定できるようになったのがジェネリクス。

スポンサードリンク

概要

型に強いのがJavaの特徴

例えば、String型の変数にintの値を代入しようとすると
コンパイルエラーとなりコンパイルすらできない。
こんなふうに、型に対して強いの(安全なの)がJavaの大きな特徴。

スクリプト言語などは、型をうっかり間違えても実行時までわからない。
一方Javaでは、型に関するチェックをコンパイル段階で行われる。
これは、他の言語と比べてもJavaの大きな強みの一つ。

JavaSE1.5より前では、型に強いことがあだとなってしまいキャストしていた

次のコードは、JavaSE1.5より前ではよく見かけた。

List noGenericsList = new ArrayList();
noGenericsList.add("巨人");
noGenericsList.add("阪神");
noGenericsList.add("広島");
 
for (Iterator iterator = noGenericsList.iterator(); iterator.hasNext();) {
    String str = (String) iterator.next();
    System.out.println(str);
}

Listクラスは、どんなものでも対応するためにObjectクラスのインスタンスを受け取るように設計されてた。
よって、どんなオブジェクトでも挿入できるが、走査するときにはキャストも必要だった。
これでは、型に強いのが台無し。

運用上も他のクラスのインスタンスを一つのコレクションにまとめることなんかほとんどない。
でもしょうがないから、いちいちキャストしていた。ほんとムダなコード。

例えば、String型に対応するListクラスを定義していけばいけそうに思えるが、
結局他のクラスに対応できないので、存在するクラスの数だけ必要になっちゃうからダメだった。

型に対する強さを残しつつ、特定の型にも対応するためのジェネリクス

こんな状態を打破してくれたのがジェネリクス。
型を変数のようにパラメータ化して、クライアント側が設定できるようになった。

List<String> genericsList = new ArrayList<>();
genericsList.add("巨人");
genericsList.add("阪神");
genericsList.add("広島");
 
for (String str : genericsList)
    System.out.println(str);

アクセス修飾子のまとめ

アクセス修飾子は、
クラス宣言で利用できるものと
フィールド・メソッドで利用できるものが違う。

クラス宣言で利用できるアクセス修飾子
修飾子 概要
public すべてのパッケージからアクセス可能。
(無指定) 同じパッケージ内(そのクラスも含め)であればアクセス可能。
他のパッケージからはアクセスできない。
フィールド・メソッドで利用できるアクセス修飾子
制限 修飾子 概要

|
|
|
|
|
|
public すべてのパッケージからアクセス可能。
protected 同じパッケージ内(そのクラスも含め)+サブクラスからアクセス可能。
サブクラスの場合は、他のパッケージであってもアクセス可能。
(無指定) 同じパッケージ内(そのクラスも含め)であればアクセス可能。
他のパッケージからはアクセスできない。
private そのクラス内のみアクセス可能。
他のクラスからはアクセスできない。

スポンサードリンク

基本

プリミティブ型の一覧

全部で8種類。

型名 値域 デフォルト
boolean true,false false
char \u0000~\uFFFF \u0000
byte -128~127 ±約120 0
short -32768 ~ 32767 ±約3万2000 0
int -2147483648 ~ 2147483647 ±約21億4000万 0
long -9223372036854775808
~ 9223372036854775807
±約-922京3372兆 0
float ±1.4E-45 ~ ±3.4028235E+38 IEEE単精度32ビット浮動小数点 0.0
double ±4.9E-324
~ ±1.7976931348623157E+308
IEEE倍精度64ビット浮動小数点 0.0

例外は継承するクラスによっても性質が変わるので
全体像を押さえるのがまず重要。

例外の発生しないアプリケーションはないので、
うまく付き合うことが必要。

例外クラスの構成

次のような構成になっている。

例外クラス図

例外クラスは4つのクラスのいずれかを継承することになるので、
まずはこれらの把握する。

Throwable

すべての例外クラスの親クラス。

Throwableを継承していないとthrowできないので、
例外クラスは必ずThrowableを継承する。

Error

JVMに関する例外。

このクラスを継承した例外が発生した場合は、
JVMで異常が発生していることになる。

よってJVMの作成者以外は、
Errorを継承する例外クラスを作る必要はない(作るべきではない)。

Exception

プログラムに関する例外クラス。

Exceptionを継承するクラスを利用する場合は、
必ず例外処理をする必要がある。
(しないとコンパイルエラーとなる。)

RuntimeException

プログラムに関する例外クラス。

RuntimeExceptionを継承するクラスを利用する場合は、
例外処理を必ずしもしなくてもよい。

例外を利用する

Java標準ライブラリに定義されている例外クラス

Javaでは標準ライブラリには、
既に多くの例外クラスが定義されている。

これらはJVMや標準ライブラリの構成上必要なために存在するが、
別に自由に利用して問題ない。

よく利用される例外クラス
パッケージ 例外クラス 概要
java.lang IllegalArgumentException 不正な引数が渡された場合に投げる。
llegalStateException 不正な状態に陥った場合に投げる。
IndexOutOfBoundsException インデックスが範囲外になった場合に投げる。
NullPointerException nullに対してメソッドなどを呼び出そうとした場合に投げる。
UnsupportedOperationException サポートしていないメソッドが呼び出された場合に投げる。

例外を自作する

例外を自ら作成する場合は、
例外クラスを継承しなくてはいけない。

Errorを作ることは基本的にないので、
「Exception」か「RuntimeException」のどちらか
またはこれらのサブクラスを継承することになる。

どのクラスを継承するかによって、
扱いが大きく違うので注意する。

ExceptionとRuntimeExceptionが運命の分かれ道

「Exception」と「RuntimeException」のどちらを継承しているかによって
コンパイラの扱いが変わってしまう。

Exceptionの場合は、
例外処理(try-catchかthrows)を記述しないとコンパイルエラーになる。
よって、利用する側が例外処理を必ず行うことになる。

一方RuntimeExceptionは、
例外処理を記述しなくてもコンパイルエラーとはならない。
よって、利用する側が例外処理を行うかどうかを決める。

キーワードというわけではなくクラスが違うだけで
コンパイラにおける扱いが異なってしまう。

よって、この違いをきっちりと理解して使い分けることが
例外設計の第一歩となる。