目次
背景
- SpringでAPIを管理する必要があった
- Javaは十年ぶりなので備忘録をまとめた
Javaとは
Javaのエディション
- Java SE(Java Platform, Standard Edition)
- 標準的なエディション
- Java EE(Java Platform, Enterprise Edition)
- 企業向け大規模エディション
- Java ME(Java Platform, Micro Edition)
- 組み込み向けエディション
なお、Java 9 以降はJava EE は Jakarta EE の名称に変更された。
開発の管理は、OracleからEclipse Foundationになった。
JDKとJRE
- JRE(Java Runtime Environment)
- Javaの実行環境
- JDK(Java Development Kit)
- Javaの開発環境。JREを含む
Oracle JDKとOpenJDK
- Oracle JDKは最初は無償だったが2018年に有償化された
- OpenJDKは、Oracleの他、Red Hat、IBM、Apple、SAPなども参加するコミュニティで開発
文法
リテラル
リテラルは次の4つ。
- 数字リテラル
- 整数リテラル: int型として扱われるが、接尾辞を付けることでlong型としても扱える(例:
123L
) - 浮動小数点リテラル: double型として扱われるが、接尾辞を付けることでfloat型としても扱える(例:
1.23f
)
- 整数リテラル: int型として扱われるが、接尾辞を付けることでlong型としても扱える(例:
- 文字・文字列リテラル
- 文字リテラル: 単一のUnicode文字を表現し、char型として扱われる(例:
'あ'
) - 文字列リテラル: 複数の文字を連結したものを表現し、String型として扱われる(例:
"あ"
) - テキストブロック: Java 13以降で導入され、複数行の文字列を簡単に扱うことができる(例:
"""あ"""
)
- 文字リテラル: 単一のUnicode文字を表現し、char型として扱われる(例:
- 論理値リテラル
- boolean型として扱われ、trueまたはfalseの値を取る
- 特殊リテラル
- nullリテラル: オブジェクト参照が存在しないことを示し、nullとして扱われる
プリミティブ
プリミティブ型(基本データ型)の一覧は以下。
種別 | 型 | 説明 |
---|---|---|
論理値 | boolean | 真偽値。true または false。 |
文字 | char | 2バイトUNICODE文字。'\u0000'~'\uffff'。 |
整数 | byte | 1バイト符号付整数。-128~127。 |
short | 2バイト符号付整数。-32768~32767。 | |
int | 4バイト符号付整数。-2147483648~2147483647。 | |
long | 8バイト符号付整数。約-922京~約922京。 | |
浮動小数 | float | 4バイト浮動小数点数。 |
double | 8バイト浮動小数点数。 |
列挙型
Java5からサポートされた列挙型。
|
|
引数を設定する事もできる。
|
|
型の調べ方
instanceofを使う方法
|
|
getClassを使う方法
|
|
その他にはReflectionを使う方法もある。
キャスト
値型(プリミティブ型)
明示的なキャスト(大きな型から小さな型)
|
|
暗黙的なキャスト(小さな型から大きな型)
|
|
参照型(オブジェクト)
アップキャスト(サブクラスからスーパークラスへ)される。
|
|
ダウンキャスト(スーパークラスからサブクラスへ)は明示的に型を指定する。
|
|
ボクシング
Boxingは、基本データ型(int、double、booleanなど)を、対応するラッパークラス(Integer、Double、Booleanなど)に変換すること。
|
|
メソッドやコレクションの要素は、ラッパークラスを使うことが推奨される。
|
|
修飾子
修飾子一覧
以下が修飾子一覧。
修飾子 | クラス | インタフェース | メソッド | コンストラクタ | ブロック | 変数 | 説明 |
---|---|---|---|---|---|---|---|
public | ○ | ○ | ○ | ○ | × | ○ | アクセス修飾子 |
protected | × | × | ○ | ○ | × | ○ | アクセス修飾子 |
private | × | × | ○ | ○ | × | ○ | アクセス修飾子 |
static | × | × | ○ | × | × | ○ | スタティック修飾子 |
final | ○ | × | ○ | × | × | ○ | ファイナル修飾子 |
abstract | ○ | ○ | ○ | × | × | × | 抽象修飾子 |
native | × | × | ○ | × | × | × | ネイティブ修飾子 |
synchronized | × | × | ○ | × | ○ | × | 同期修飾子 |
transient | × | × | × | × | × | ○ | 一時的修飾子 |
volatile | × | × | × | × | × | ○ | 揮発性修飾子 |
strictfp | ○ | ○ | ○ | × | × | × | 厳密浮動小数修飾子 |
アクセス修飾子
Javaはアクセス修飾子による制限は、パッケージの階層に関係なく同一パッケージか異なるパッケージかで決まる。
アクセス修飾子 | 自クラス | 同パッケージ | サブクラス(同パッケージ) | 他クラス(同パッケージ) | サブクラス(他パッケージ) | 他クラス(他パッケージ) |
---|---|---|---|---|---|---|
public | ○ | ○ | ○ | ○ | ○ | ○ |
protected | ○ | ○ | ○ | ○ | ○ | × |
なし(package-private) | ○ | ○ | ○ | ○ | × | × |
private | ○ | × | × | × | × | × |
なお、interfaceはデフォルトでabstruct
であり、メソッドはデフォルトでpublic abstruct
になっている。
|
|
const
実質的に、final
+ static
= const
。
|
|
クラス
クラス
クラスは、オブジェクト(インスタンス とも)が持つ、フィールド(属性、アトリビュート、プロパティ、メンバ変数)や、メソッド(関数、メンバ関数)などを定義する。
|
|
インスタンス化
|
|
コンストラクタはあるがデストラクタはない。
|
|
クラス修飾子
- クラスの修飾子には、public、final、abstract、strictfp を指定することができる
- インナークラスでは、protected、private、static を指定することが可能となる
継承
|
|
superで親クラスを呼び出せる。
|
|
インスタンスが、指定したクラスまたはその上位のクラスに属しているかどうかはinstanceofを使う。
|
|
匿名内部クラス
次の場面では、クラスに名前をつけること無くクラスを定義してインスタンスを生成する事が可能
- あるクラスの派生クラスのオブジェクトを一つだけインスタンス化する場合
- あるインターフェイスを実装して一つだけインスタンスを作成する場合
例
|
|
ジェネリクス
ジェネリクスの例
任意の型を受け付けるクラス・メソッドに対して特定の型を割り当てて、型専用のクラスを生成する。
|
|
ジェネリクスの用語
用語 | 例 | 説明 |
---|---|---|
ジェネリック型(generic type) | List<T> | 型引数を持つクラスやインタフェース。 |
仮型パラメータ(type parameter) | T | ジェネリック型の宣言時に使われる型のプレースホルダー。 |
パラメータ化された型(parameterized type) | List<String> | 実際の型引数を使用してインスタンス化されたジェネリック型。 |
実型パラメータ(actual type parameter) | String | パラメータ化された型の具体的な型引数。 |
原型(raw type) | List | 型引数を使用しないジェネリック型。非ジェネリック型と同様に扱われる。 |
境界型パラメータ(bounded type parameter) | <E extends Number> | 特定のクラスやインタフェースを拡張または実装する型に制限された型パラメータ。 |
非境界ワイルドカード型(unbounded wildcard type) | List<?> | 任意の型を許容するワイルドカード型。 |
境界ワイルドカード型(bounded wildcard type) | List<? extends Number> , List<? super Number> | 特定のクラスやインタフェースを拡張する型を許容するワイルドカード型。 |
原型の注意
- なお、原型ではコンパイラによる型安全性は提供されない
- そのため、原型よりも非境界型ワイルドカードを利用することが推奨されている
- 原型がJavaに残っているのは、Java 4以前への後方互換性を維持するため
ワイルドカード型
3つのワイルドカード型
Javaには次の3つのワイルドカード型(<?>
)がある。
- 非境界ワイルドカード型 (unbounded wildcard type)
- 具体例:
List<?> list
- 具体例:
- 境界ワイルドカード型 (bounded wildcard type)
- 上限境界ワイルドカード型 (upper bounded wildcard type)
- 具体例:
List<? extends Number> list
- 具体例:
- 下限境界ワイルドカード型 (lower bounded wildcard type)
- 具体例:
List<? super Number> list
- 具体例:
- 上限境界ワイルドカード型 (upper bounded wildcard type)
ジェネリック型の継承関係
Javaでは型パラメータ同士に継承関係があっても、ジェネリックス型自体には継承関係はない。
このジェネリックス型の性質(変性)を不変という。
|
|
非境界ワイルドカード型
しかし、非境界ワイルドカード型はすべてのパラメータ化された型のスーパータイプとなる。
そのため、どんなList
も、List<?>
に代入できる。
|
|
これがワイルドカード型の正体。
非境界ワイルドカード型の制限
非境界ワイルドカード型は、任意のパラメータ化された List のスーパータイプとなり便利に利用できる一方、以下のような制限がある。
- メソッドの戻り値に使われている
T
はObject型になる - メソッドの引数に使われている
T
にはnullリテラルしか渡せない
|
|
getValueの例
|
|
- 非境界ワイルドカード型のメソッドの戻り値として許されるのは Object のみという事
- 何が入っているかは分からないが、すべての参照型は Object のサブタイプであるから
次はsetValueの例
|
|
- 非境界ワイルドカード型のメソッドの引数に使われている
T
型にはnull
リテラルしか代入できない - なぜなら、
null
はJavaの仕様上、null
型という特殊な型の唯一の値であり、どんな参照型の変数に代入できることが定められているから
境界型ワイルドカード型
境界ワイルドカード型はパラメータ化されたそのジェネリックス型の一部のスーパータイプの事。
このとき、境界型ワイルドカードは以下のように定義される。
- 上限境界
- ある型のサブタイプでパラメータ化された、そのジェネリックス型のスーパータイプ
- 具体例:
List<? extends Number>
Number
のサブタイプでパラメータ化されたList
のスーパータイプとなる型
- 下限境界型
- ある型のスーパータイプでパラメータ化された、そのジェネリックス型のスーパータイプ
- 具体例:
List<? super Number>
Number
のスーパータイプでパラメータ化されたList
のスーパータイプとなる型
上限境界型の性質は次の図となる。
一方、下限境界型の性質は次の図となる。
コードとしては次となる。
|
|
境界型ワイルドカード型の制限
境界ワイルドカード型を使うと、型安全のために存在している非境界ワイルドカード型の制限を緩和することができる。
上限境界型のメリット
- 「メソッドの戻り値に使われている
T
はObject
型になる」という制限が緩和される - つまり、「メソッドの戻り値に使われている
T
はNumber
型になる」 - 理由
- 上限境界型ワイルドカード(
<? extends Number>
)は、指定された型T
またはそのサブタイプを表す - そのため、コンパイラはその型がNumber型またはそのサブタイプであることを保証できる
- 上限境界型ワイルドカード(
下限境界型のメリット
- 「メソッドの引数に使われている
T
にはnull
リテラルしか渡せない」という制限が緩和される - つまり、「メソッドの引数に使われている
T
にはNumber
が渡せる」 - 理由
- 限境界型ワイルドカード(
<? super Number>
)は、指定された型T
またはそのスーパータイプを表す - そのため、Number型またはそのスーパータイプ(Object等)のオブジェクトを引数として渡すことができる
- 限境界型ワイルドカード(
これが境界型ワイルドカード型の利点。
変性
3つの変性
変性(variance)とは、ジェネリクスにおいて、異なる型パラメータを持つ型の間で、代入の可能性や互換性を表す概念。
変性 | 例 |
---|---|
共変/共変性(Covariance) | List<Integer> がList<Number> のサブタイプ |
反変/反変性(Contravariance) | List<Number> がList<Integer> のサブタイプ |
非変/非変性(Invariance) | List<Number> とList<Integer> の継承関係はない |
NOTE: IntegerクラスはNumberクラスのサブクラス
- Javaは非変タイプのジェネリクスになる
- つまり、
List<Integer>
はList<Number>
のサブクラスとはならない - 故に、下のコードはコンパイルエラーになる
|
|
Put/Get 原則
このPut/Getの原則は、共変性(covariance)と反変性(contravariance)をどのように適用するかを説明するための用語。
- PECS(Producer Extends, Consumer Super):
- Producer Extends: 何かを生成する(出力する)場合は、extends キーワードを使う
- Consumer Super: 何かを消費する(入力する)場合は、super キーワードを使う
Producer Extendsパターン
|
|
Consumer Superパターン
|
|
レコードクラス
レコードクラス
Java 16 でサポートされた機能で、下記の特徴を持つクラスを生成する
- コンストラクタで指定した値をイミュータブル(変更不可)なフィールドとして保持する
- フィールド名と同じアクセッサメソッドを持つ
- toString(), equals(), hashCode() メソッドを持つ
|
|
上のコードは下と同じ
|
|
lombok
lombokのアノテーションでもrecordクラスと同じ事ができるので、それでも良い。
|
|
これは次のコードと同等の定義となる。
|
|
ラムダ式
ラムダ式
Java 8 で ラムダ式 がサポートされた。
|
|
上のコードは下のlambda式でかける。
|
|
JavaのLambdaは、単一の抽象メソッドを持つインタフェースを実装した無名クラスのインスタンスを生成する式となる。
関数型インタフェース
関数型インタフェースは「抽象メソッドをひとつのみ持つインタフェース」の事。
|
|
下のように使える。
|
|
関数型インターフェイスのまとめ。
関数型インタフェース | 引数の型 | 戻り値の型 | メソッド名 | 説明 |
---|---|---|---|---|
Function<T, R> | T | R | R apply(T t) | T型の引数を受け取り、R型の戻り値を返す。 |
BiFunction<T, U, R> | T, U | R | R apply(T t, U u) | T型とU型の2つの引数を受け取り、R型の戻り値を返す。 |
UnaryOperator<T> | T | T | T apply(T t) | T型の引数を1つ受け取り、T型の戻り値を返す(Function<T, T>のサブインタフェース)。 |
BinaryOperator<T> | T, T | T | T apply(T t1, T t2) | T型の引数を2つ受け取り、T型の戻り値を返す(BiFunction<T, T, T>のサブインタフェース)。 |
Consumer<T> | T | なし | void accept(T t) | T型の引数を受け取り、値を返さない。 |
BiConsumer<T, U> | T, U | なし | void accept(T t, U u) | T型とU型の2つの引数を受け取り、値を返さない。 |
Predicate<T> | T | boolean | boolean test(T t) | T型の引数を受け取り、真偽を返す。 |
BiPredicate<T, U> | T, U | boolean | boolean test(T t, U u) | T型とU型の2つの引数を受け取り、真偽を返す。 |
Supplier<R> | なし | R | R get() | 引数を受け取らず、R型の戻り値を返す。 |
インターフェイス
インタフェース修飾子
- インタフェースの修飾子には、public、abstract、strictfp を指定することができる
- インタフェースをクラス内に定義する場合には protected、private、static を指定することも可能
継承と実装
継承
|
|
実装
|
|
Java8以降のinterface
Java 8以降は、インターフェースはデフォルトメソッド(default
)や静的メソッド(static
)を持つことができるようになった。
|
|
抽象クラス
抽象クラス vs. Interface
そうすると、abstruct classとの違いは何かと言うと次になる。
- 継承:
- インターフェース: 多重継承が可能
- 抽象クラス: 単一継承のみ
- フィールド:
- インターフェース: インスタンスフィールドを持てない(static finalのみ)
- 抽象クラス: インスタンスフィールドを持てる
- メソッドの実装:
- インターフェース: デフォルトメソッドを持てるが、基本的にはメソッドのシグネチャのみを定義
- 抽象クラス: 具象メソッドと抽象メソッドの両方を持てる
- コンストラクタ:
- インターフェース: 持てない
- 抽象クラス: 持てる
使用感としては次になる。
- インターフェースを使用する場合:
- クラス間で共通の契約や振る舞いを定義したい
- 多重継承が必要な場合
- 既存のクラスに新しい振る舞いを追加したい
- 抽象クラスを使用する場合:
- 部分的な実装を提供したい
- クラス群に共通の状態や動作を持たせたい
- コンストラクタや状態を持つ必要がある場合
抽象クラス vs. 具象クラス
- 抽象クラスを使用する場合:
- 部分的な実装や共通の状態・動作を提供する必要があるとき
- 基底クラスとしてのみ使用され、インスタンス化されないことを意図するとき
- テンプレートメソッドパターンを実装するとき
- 具象クラスを使用する場合:
- 完全な実装を持ち、直接インスタンス化されることを意図するとき
- 他のクラスや抽象クラスに依存せず、独立して機能するクラスを定義するとき
- 特定のオブジェクトの具体的なインスタンスを作成するとき
コレクション
代表的なコレクション
次のようなコレクションが代表的。
カテゴリ | クラス | 説明 |
---|---|---|
List系 | ArrayList | 動的配列を扱う。ランダムアクセスが高速だが、挿入・削除はリストの末尾以外では遅くなることがある |
LinkedList | 双方向連結リストを扱う。挿入・削除が高速ですが、ランダムアクセスは遅くなる | |
Vector | 動的配列を扱う。スレッドセーフだが、パフォーマンスが悪いため、現在ではあまり推奨されない古いクラス | |
Set系 | HashSet | 値の重複を許さない順不同の要素集合を扱う。内部的にハッシュテーブルを使用している |
TreeSet | 値の重複を許さないソートされた要素集合を扱う。内部的に赤黒木を使用する | |
Map系 | HashMap | キーと値の組からなる要素の集合を扱う。順序は保証されない。内部的にハッシュテーブルを使用している |
LinkedHashMap | キーと値の組からなる要素の集合を扱う。挿入順序が保証されいる | |
TreeMap | キーと値の組からなる要素の集合を扱う。キーでソートされている。内部的に赤黒木を使用している | |
Queue系 | Deque | 両端からの挿入・削除が可能なキューやスタックを扱う。Deque はインタフェースであり、ArrayDeque やLinkedList がその実装クラス |
パッケージ
Import
- import文を使用することで、繰り返し書く必要がなくなるのが目的
- 故に、importを使わずとも、クラスの完全修飾名でアクセスすればアクセスできる
- 当然、同一packageからは、そのままアクセスできる
|
|
例外
例外のクラス
以下のようなタイプのエラーがある。
クラス | 説明 |
---|---|
Error | Java仮想マシン(JVM)によって検出される致命的なエラー。通常、プログラムで回復不可能であり、例外ハンドラを記述しても処理を継続できないことが多い。例:OutOfMemoryError (メモリ枯渇)、StackOverflowError (スタックオーバーフロー)など |
RuntimeException | 実行時に発生するプログラムエラー。チェックされない例外(Unchecked Exception)であり、例外ハンドラは省略可能。例:ArithmeticException (ゼロ除算)、IllegalArgumentException (引数不正)、NullPointerException (NULLポインタ参照)、ArrayIndexOutOfBoundsException (不正インデックスによる配列参照)など |
Exception | 一般的な例外。チェックされる例外(Checked Exception)であり、例外ハンドラを記述しないとコンパイルエラーとなる。例:IOException 、SQLException など |
検査例外と非検査例外
- 検査例外(Checked Exception)はコンパイル時にチェックされる例外
- プログラムの外部的な要因(例えば、ファイルの存在しないことや、ネットワークの障害など)によって発生する可能性のある問題を扱う
下のように検査例外である、IOException
などをtry-catchで捕まえないといけない。さもなければメソッドでthrows
する必要がある。
|
|
- 検査例外は処理の奥深く(例えばDB付近)で発生し、上部(例えばAPIのController)でハンドルする場合、
- 中間で例外を
throws
でバケツリレーしなければならない時は、非検査例外を使うのがベター - もしくは、下のようにエラーを変換する
|
|