キーワード (Java)

この項目ではJavaにおける**キーワード**（予約語の記事も参照）に関して説明する。Java 25現在、予約キーワード（reserved keyword）が51個、コンテキスト・キーワード（contextual keyword）が17個ある。

予約キーワードは識別子に用いることはできない。コンテキスト・キーワードは文脈に応じて識別子に用いることができたりできなかったりする。例えばコンテキスト・キーワードの`open`はなどで識別子に用いられている。

この項目は、プログラムの細かい説明には立ち入らず、他の言語と比較できるような説明を目的としている。

## 特徴
プリミティブ型名や分岐処理 (if, switch)、反復処理 (for, while) などの基本的な構文とキーワードはC言語およびC++と共通するものが多い。クラスや例外処理に関してはC++類似の構文とキーワードが多い。

## 沿革
以下のキーワードが追加されている。
*Java Language Specification First Edition のキーワードは47個。
*J2SE 1.2で`strictfp`が追加された。
*J2SE 1.4で`assert`が追加された。
*J2SE 5.0で`enum`が追加された。
*Java 9では制限付きキーワード (restricted keyword) として、`open`, `module`, `requires`, `transitive`, `exports`, `opens`, `to`, `uses`, `provides`, `with`が10個追加された。また、Java 9では単一のアンダースコア`_`がキーワードに追加され、識別子として使用できなくなった。
*Java 10では`var`による型推論が追加されたが、これはキーワードではなく、予約された型名 (reserved type name) によって実現されている。
*Java 14で追加された制限付き識別子（キーワードではない）の`yield`は、switch式（JEP 361）で使用され、結果を返すために使用される。`var`が制限付き識別子に変更になった。
*Java 16で追加された制限付き識別子（キーワードではない）の`record`は、データキャリアとして使用される不変のデータオブジェクトを簡単に定義するために導入された。
*Java 17でキーワードが予約キーワードとコンテキスト・キーワードに分かれた。予約キーワードは従来のキーワードで識別子に使えない。Java 16まで制限付きキーワードと制限付き識別子と呼ばれていたものは統合されコンテキスト・キーワードに名称変更になり、文脈によってキーワードになる。コンテキスト・キーワードに`non-sealed`, `permits`, `sealed`が3個追加された。
** `sealed`キーワードはクラスやインターフェースに対して使用され、指定されたサブクラスのみがクラスやインターフェースを拡張または実装できるようにする。
** `permits`キーワードは`sealed`クラスの許可されたサブクラスを指定するために使用される。
** `non-sealed`キーワードは`sealed`クラスのサブクラスで、このサブクラスがさらに他のクラスによって拡張可能であることを示す。
** `var`, `yield`, `record`が制限付き識別子からコンテキスト・キーワードに変更になった。
*Java 21でJEP 441 (Pattern Matching for switch)から`when`がコンテキスト・キーワードに追加された。

## プリミティブ型
### 型名
プリミティブ型の名前である。C言語およびC++と共通するものが多い。ただし内部表現は処理系依存ではなく、言語仕様によって厳密に定められている。

* **byte**, **short**, **int**, **long**
*: 8ビット、16ビット、32ビット、64ビットの整数型。2の補数で表現される。Javaには符号なしの整数型がなく、C/C++で使われる `unsigned` はない。
* **float**, **double**
*: 32ビット単精度と64ビット倍精度の浮動小数点数型。IEEE 754準拠。
* **boolean**
*: 論理型。`boolean`はC言語（C99）における`_Bool`や、C++における`bool`に相当するが、構文上は整数型ではないため整数型との暗黙的な相互変換はできないという違いがある。
* **char**
*: 文字型。`int`および`long`には暗黙的に代入可能。C/C++の`char`とは異なり、16ビットのUnicode文字（UTF-16）を保持する。
* **void**
*: これはプリミティブ型ではないが、型と同じ文脈で使うキーワードなのでここに分類する。メソッドに戻り値がないことを宣言する。void (コンピュータ)も参照のこと。

### 値（キーワードではない）
以下はキーワードであるかのように扱われるが、キーワードではなく、定義では論理値リテラル、またはnullリテラルというリテラルである。
* **true**, **false**
*: 論理値を表すリテラル。
* **null**
*: null型という特殊な型のリテラル。Nullも参照。

## モジュール
モジュールでは以下のキーワードが使われている。
* **module**
* **open**
* **opens**
* **exports**
* **provides**
* **requires**
* **to**
* **uses**
* **with**
* **transitive**

## パッケージ
* **package**
*: 自クラスのパッケージを宣言する。Javaではパッケージと呼ばれるツリー構造でクラス群を分類している。クラスやメンバに (後述する `public`, `protected`, `private`) を付けることにより、パッケージ内外でクラスやクラスのメンバにアクセス可能な範囲が変わってくる。
* **import**
*: 自クラスの所属するパッケージとは異なるパッケージにあるクラスを使用するときにこの宣言でインポートする。

## クラス
* **class**
*: クラスの定義。例えば、以下のように宣言する。それぞれについてはこの後、説明する。
*;例
*:# 
```java
public class クラス名 { ... }
```

*:# 
```java
public class クラス名 extends 親クラス名 { ... }
```

*:# 
```java
public class クラス名 implements インタフェース名1, インタフェース名2, ... { ... }
```

*:# 
```java
public class クラス名 extends 親クラス名 implements インタフェース名1, ... { ... }
```

* **interface**
*: インタフェースの定義。Javaのインタフェースとは、定義のみで実装をもたない抽象型であり、型の多重継承に使用される。インタフェースのインスタンスを直接生成することはできない。サブクラスでインタフェースを実装して使用する。実装するインタフェースはカンマ区切りで複数並べることができる。
*;例
*:# 
```java
public interface インタフェース名 { ... }
```

*:# 
```java
public interface インタフェース名 extends 上位インタフェース名1, 上位インタフェース名2, ... { ... }
```

* **extends**
*: `class` の宣言で他のクラスを継承するときに使用する。Javaのクラスは1つのスーパークラスのみ継承可能で、多重継承（実装の多重継承）はできない (参考: 菱形継承問題)。`interface`の宣言では一つ以上のインタフェースを継承するときに使用する。インタフェースがインタフェースを継承するだけなので、こちらの場合は多重継承が可能。
* **implements**
*: `class` の宣言で、インタフェースを実装するときに使用する。カンマ区切りで並べた複数のインタフェースを実装することができる。
* **enum**
*: 列挙型
* **[[this (プログラミング)|this]]**
*: 自クラスを明示するときに使用する。コンストラクタ内から他の引数のコンストラクタを呼ぶときに使用するのが一般的である。また、例えば、コンストラクタの場合は`this(引数)`、メソッドの場合は`this.メソッド名(引数)`などのように使い、親クラスに同一名・同一引数のメソッドがあるときに明示的に区別できるようにする。こちらは、ローカル変数や同じクラス内メソッドや上位クラスに同名のメソッドが存在しない場合は`this`を省略できる。内部クラスのコード領域で外部クラスのインスタンスへの参照を得るときの構文（`OuterClass.this`）でも使用される。
* **super**
*: 上位クラスのコンストラクタ、フィールド、メソッドにアクセスするときに使用する。上位クラスのコンストラクタを呼び出すときは単に`super(引数)`と書き、メソッドを呼び出すときは`super.メソッド名(引数)`などのように使う。フィールドやメソッドの場合は、自クラスに同一のものがない場合は`super`の記述を省略できる。
* **new**
*: コンストラクタの呼び出し。インスタンスを生成するときに使用する。
*;例
*:# 
```java
SampleClass s = new SampleClass();
```

*:# 
```java
int[] numbers = new int[5]; // int型の配列を生成
```

*:# 
```java
List<String> list = new ArrayList<>(); // ジェネリッククラスのインスタンス化
```

* **instanceof**
*: 指定されたクラスのオブジェクトかどうか、あるいは指定されたインタフェースを実装しているオブジェクトかどうかを判定する。`a instanceof ClassName` とした場合、`a` が `ClassName` のオブジェクトか、その派生クラスのオブジェクトであれば `true` になる。`ClassName` の箇所にオブジェクトの変数名を記述することはできない。
* **record**
*: record キーワードは、レコード型と呼ばれる新しい種類の型を定義するために使用される。レコード型は、従来のクラスと似ているが、いくつかの重要な違いがある。
*:* レコード型は、コンストラクタ、フィールド、アクセサメソッドを自動的に生成する。
*:* レコード型は、イミュータブル（変更不可）である。
*:* レコード型は、簡潔で読みやすいコードを作成するために使用できる。
*;例
*:
```java
record Person(String name, int age) {
  /* コンストラクタ、フィールド、アクセサメソッドは自動的に生成される */
}
```

* **sealed**
*: sealed キーワードはクラスやインターフェースに対して使用され、指定されたサブクラスのみがクラスやインターフェースを拡張または実装できるようにする。これにより、クラス階層の管理が厳密に行えるようになる。
*;例
*:
```java
public sealed class Shape permits Circle, Square {
  // クラスの内容
}
```

* **permits**
*: sealed クラスの許可されたサブクラスを指定するために使用される。
*;例
*:
```java
public sealed class Shape permits Circle, Square {
  // クラスの内容
}
```

* **non-sealed**
*: sealed クラスのサブクラスで、このサブクラスがさらに他のクラスによって拡張可能であることを示す。
*: non-sealed は単一の識別子ではなく、トークンシーケンスでコンテキスト・キーワードと呼ばれる。
*;例
*:
```java
public non-sealed class Circle extends Shape {
  // クラスの内容
}
```


## 修飾子
クラス、メンバの宣言に付けられる修飾子である。

* **public**, **protected**, **private**
*: クラス、メンバのアクセス制御を指示する修飾子（）である。外部からアクセス可能な範囲を決める。Javaでは4つの段階が設けられ、以下の番号が大きくなるほど外部からのアクセスが制約される。
*:# `public`では、すべてのクラスからアクセスできる。
*:# `protected`では、同一パッケージにあるクラスかサブクラスからのみアクセスできる。異なるパッケージでサブクラスでないクラスからはアクセスできない。クラスを修飾することはできない (内部クラスは例外)。
*:# アクセス修飾子がない場合は、同一のパッケージ内のクラスからのみアクセスできる。サブクラスであってもパッケージが異なる場合はアクセスできない。
*:# `private`では、他のクラスからはアクセスできず、自クラスからのみアクセスできる。クラスに修飾することはできない (内部クラスは例外)。
*:# Java SE 1.0では`private protected`という組み合わせを使用して、自分自身とサブクラスからのアクセスができるが同じパッケージ内の他のクラスからはアクセスできないというアクセス権を使用することができたが、これはJava SE 1.1以降から廃止され利用することができなくなった。
* **final**
*: フィールドに付けられた場合は再代入を禁止する。メソッド宣言に付けられた場合は、下位クラスで上書きできないことを表す。クラス宣言に付けられた場合は、継承できないことを表す。なお、Javaでは、`final`宣言されたフィールドで、宣言部では初期化せずコンストラクタ内で1回だけ代入できる記述も行える。`abstract`との併用はできない。メソッドの引数やローカル変数に使用すればその引数やローカル変数に対して再代入を許さないため、堅牢性の高いメソッドを作ることができる。`final`修飾子はイミュータブル (不変)なクラスを実装するときに役立つ。

例1:

```java
public class SampleClass {
    final int constantValue = 5;
}
```


例2:

```java
public class SampleClass {
    final int constantValue; // 初期化なし

    // コンストラクタ
    public SampleClass() {
        constantValue = 5;  // 1回だけ代入できる。
    }
}
```


* **static**
*: フィールドに付けられた場合は、クラスに属する変数（クラス変数、静的フィールド、クラスフィールド）が確保されることを表す。この修飾子のついたフィールドは、インスタンスがいくつ生成されてもフィールドの実体は1つで、すべてのインスタンスの間で共有される。

記述例:

```java
class SampleClass {
    static String shared = "shared";
    static final String STR = "constant";
}
```


:: メソッドに付けられた場合は、オブジェクトを生成しなくても直接呼び出せるメソッド（静的メソッド、クラスメソッド）であることを表す。手続き型言語の関数と同じ扱いになる。

例:

```java
class Sample1 {
    // static なメソッド
    public static void method() { ... }
}

class Sample2 {
    void proc() {
        ...
        Sample1.method(); // インスタンスを生成せず直接実行できる。
        ...
    }
}
```


:: クラス内に`static {...}`というブロックが現れた場合は、そのクラスが最初に参照されたときにそのブロック内のコードを実行する。これを静的初期化子と呼び、主にstatic finalな配列やオブジェクトの初期化などに利用される。データベースにアクセスするためにJDBCドライバを呼び出すもこの静的初期化子を呼び出している。

例:

```java
class StaticInitSampleClass {
    private static final List<String> list;

    static {
        final List<String> tempList = new ArrayList<>();
        tempList.add("Hello,");
        tempList.add("World.");
        StaticInitSampleClass.list = Collections.unmodifiableList(tempList);
    }
}
```


内部クラス
:: 入れ子にされたクラス（ネストされたクラス: nested class）のうち、`static`修飾されていないものは内部クラス (inner class) と呼ばれ、暗黙的に外側のクラスのインスタンスをキャプチャして参照することができるが、このネストクラスを`static`修飾すると静的ネストクラス (static nested class) となり、暗黙的に外側のクラスのインスタンスを参照できなくなる。

例:

```java
class OuterClass {
    static int outerStaticField = 0;
    int outerField = 0;

    class InnerClass {
        void setOuterField(int value) {
            outerField = value; // 暗黙参照可能。
            outerStaticField = value; // OK。
        }
    }

    static class StaticClass {
        void setOuterField(int value) {
            //outerField = value; // コンパイルエラー。
            outerStaticField = value; // OK。
        }
    }

    public OuterClass() {
        new InnerClass().setOuterField(100);
        new StaticClass().setOuterField(-100);
    }

    public static void test() {
        final OuterClass outer = new OuterClass();
        System.out.println("OuterField = " + outer.outerField);
        System.out.println("OuterStaticField = " + outerStaticField);
    }
}
```


* **abstract**
*:クラスまたはメソッドに付けられる修飾子である。`final`と併用することはできない。Javaでは、実装されないメソッドがあるクラスを作成することができる。抽象クラス自身のインスタンスを作成することはできない。似たものとしてインタフェースがあるが、`abstract class`は以下の点においてインタフェースと異なる。
*:* コンストラクタを持つことができる
*:* メソッドなどの実装を記述できる
*:* インスタンス変数を持つことができる
*:`abstract class`はそのままではインスタンス化できず、不足しているメソッドを実装した派生クラスを用意して使用する。

記述例:

```java
public abstract class Sample {
    // 実装があるメソッド
    public void method1() {
        ...
    }
    // 実装がないメソッド
    public abstract void method2();
}
```


* **native**
*: メソッドがJava言語以外で実装されていることを宣言する（Java Native Interfaceを参照）。
* **synchronized**
*: メソッドの宣言や特定のブロックに付けられ、排他制御を指示する。同一オブジェクトが複数のオブジェクトから参照され、異なるスレッドで同時に処理を行っている場合でも、この修飾子があるブロックでは処理を行えるスレッドはただ1つしか存在しない。

記述例1:

```java
public synchronized void method() { ... }
```


記述例2:

```java
public void method() {
    ...
    synchronized(this) { // 自クラスのインスタンスに対して排他制御
        // 排他制御されるブロック
    }
    ...
}
```


記述例3:

```java
public void method(Object obj) {
    ...
    synchronized(obj) { // Object obj に対して排他制御
        // 排他制御されるブロック
    }
    ...
}
```


* **volatile**
*: フィールドの宣言に付けられ、キャッシュを見に行かずに常に最新の値を見に行くようになる。マルチスレッド下における軽量かつ限定的な同期処理に使われる。

例:

```java
public class SampleClass {
    volatile int syncSample;
    ...
}
```


* **transient**
*: フィールドの宣言につけられる。Javaにはオブジェクトをそのままネットワークに送信したりファイルなどに保存したりするためのシリアライズと呼ばれる機能があり、`transient`は対象フィールドがシリアライズの対象にならないことを指示する。スレッドオブジェクトなど、保存できないフィールドや保存されると不都合なフィールドに対して使用される。

## 制御構造
C言語およびC++と共通のキーワードを使用している。

* 分岐
** **if**, **else**
** **switch**, **case**, **when**, **default**
* 繰り返し
** **for**, **while**, **do**
* ジャンプ
** **continue** - ループの現在の反復 (iteration) をスキップする
** **break** - ループのブロックから抜け出す
** **return** - メソッドから抜け出す。戻り値のあるものは値やオブジェクトの参照を返す。
** **yield** - switch式の値を返す。

## 例外処理
例外処理はC言語にはない。Javaでは、C++およびC#とほぼ共通の構文およびキーワードが使用されている。ただしfinallyはC++には存在せず、throwsはC#には存在しない。

* **try**, **catch**, **finally**
*: 例外が発生しうる箇所で使用する。tryブロック (`try{`と`}`との間) で例外が発生しうるコードを囲み、catchブロック (`catch(`の派生クラス例外オブジェクト`){`と`}`との間) に例外発生後の処理を書く。finallyブロック (`finally{`と`}`との間) には、ファイルのクローズ、データベースセッションの切断、ログアウトなど、例外発生の有無にかかわらずtry/catchブロック内の処理を終了する前に必ず実行しておきたいコードを書く。catchを記述した場合finallyは省略可能であり、finallyを記述した場合catchは省略可能である。try/catchブロックとfinallyブロックの両方にreturn文がある場合、後者が優先される。catchブロックにはif-else-if文のように連続して捕捉したい例外を記述することができる。
* **throw**
*: 例外を発生させる。
* **throws**
*: メソッドの宣言で使用される。そのメソッドがどのような例外をスローするかを列挙する。Javaにおける例外の種類には大きく分けて
*:#`throws`の明示が必要なを継承していない例外
*:#`throws`の明示が必要でないを継承している例外
*:がある。前者は主にファイルエラーなどプログラムの動作中にその都度対応すべき例外で、後者は主に開発・デバッグの段階で対処すべき例外あるいは深刻なエラーである。

以下はを使った記述例である。

```java
public void method() throws Exception { // メソッドが例外をスローすることを宣言
    try {
        ...
        if (エラー条件) {
            throw new IOException(); // 例外を発生させる。
        }
        // (1) 正常終了
        // このtryブロックにはreturn文を記述することもできる。
        // ただし、finallyブロックにすでにreturn文があるときは、ここにreturn文を書いてもfinallyブロックのreturnが優先される。
    } catch (IOException e) { // IOException は Java の例外クラスの1つ
        // (2) 例外処理
        // このcatchブロックにはreturn文を記述することもできる。
        // ただし、finallyブロックにすでにreturn文があるときは、ここにreturn文を書いてもfinallyブロックのreturnが優先される。
    } catch (Exception e) { // IOException よりも上位（親）の例外クラス
        // (3) 例外をさらに外のブロックにスローする。
        throw e;
    } finally {
        // (1), (2), (3) どの場合でもこのブロックは必ず実行される。
        // ここにreturn文があるときはtry/catchブロックにreturn文があろうともこちらのreturn文が優先される。
        ...
    }
}
```


## assert
* **assert**
*: assert 違反時に  を投げる。

## 型の省略
* **var**
*: ローカル変数およびラムダ式の引数で型を省略する際に var を使用する。Java 10以降で使用可能。

## 変数名の省略
* **_**
*: 変数名を省略する場合に使用する。Java 22以降で使用可能。

## 浮動小数点演算
浮動小数点演算の移植性を高める`strictfp`がある。浮動小数点の演算では一般に全く同じ結果は期待できないものではあるが、x87などハードウェアによっては、途中の値においてより高い精度や、より広い値の範囲で演算が行われるために、最終結果が他のプラットフォームと一致しない場合があり、特にIEEE 754を前提として予想される結果から外れることが問題である。

strictfpを指定すると、途中結果についても全てIEEE 754の倍精度を強制し、相異なるプラットフォーム同士の間でも演算結果が一致することを保証するとされている（仕様では FP-strict という用語を使っている）。Java VMの実装で、これを正しく実現するには、x86系CPUを使った計算機の場合、x87を避けてSSE2で計算するか、それができない場合は特殊なテクニックが必要である。

なお、同様に移植性のある結果を保証するというクラスがあるが、そちらはFDLIBMというSun製のライブラリと同じ結果を保証するとされている。

Java 17以降は常に`strictfp`を付けたときの挙動と同じになった。x86系CPUでは常にSSE2以降を使用して計算する。

## 未使用
`const`、`goto`がキーワードとして予約されているが、Javaでは使用できない。使用するとコンパイル時に構文エラーになる。

## 脚注

### 注釈

### 出典

## 参考文献

*
*