この項目ではJavaにおけるキーワード(予約語の記事も参照)に関して説明する。Java 25現在、予約キーワード(reserved keyword)が51個、コンテキスト・キーワード(contextual keyword)が17個ある。
予約キーワードは識別子に用いることはできない。コンテキスト・キーワードは文脈に応じて識別子に用いることができたりできなかったりする。例えばコンテキスト・キーワードのopenはServerSocketChannel.open()などで識別子に用いられている。
この項目は、プログラムの細かい説明には立ち入らず、他の言語と比較できるような説明を目的としている。
プリミティブ型名や分岐処理 (if, switch)、反復処理 (for, while) などの基本的な構文とキーワードはC言語およびC++と共通するものが多い。クラスや例外処理に関してはC++類似の構文とキーワードが多い。
以下のキーワードが追加されている。
strictfpが追加された。assertが追加された。enumが追加された。open, module, requires, transitive, exports, opens, to, uses, provides, withが10個追加された。また、Java 9では単一のアンダースコア_がキーワードに追加され、識別子として使用できなくなった。varによる型推論が追加されたが、これはキーワードではなく、予約された型名 (reserved type name) によって実現されている。yieldは、switch式(JEP 361)で使用され、結果を返すために使用される。varが制限付き識別子に変更になった。recordは、データキャリアとして使用される不変のデータオブジェクトを簡単に定義するために導入された。non-sealed, permits, sealedが3個追加された。
sealedキーワードはクラスやインターフェースに対して使用され、指定されたサブクラスのみがクラスやインターフェースを拡張または実装できるようにする。permitsキーワードはsealedクラスの許可されたサブクラスを指定するために使用される。non-sealedキーワードはsealedクラスのサブクラスで、このサブクラスがさらに他のクラスによって拡張可能であることを示す。var, yield, recordが制限付き識別子からコンテキスト・キーワードに変更になった。whenがコンテキスト・キーワードに追加された。プリミティブ型の名前である。C言語およびC++と共通するものが多い。ただし内部表現は処理系依存ではなく、言語仕様によって厳密に定められている。
以下はキーワードであるかのように扱われるが、キーワードではなく、定義では論理値リテラル、またはnullリテラルというリテラルである。
モジュールでは以下のキーワードが使われている。
public class クラス名 { ... }public class クラス名 extends 親クラス名 { ... }public class クラス名 implements インタフェース名1, インタフェース名2, ... { ... }public class クラス名 extends 親クラス名 implements インタフェース名1, ... { ... }class の宣言で、インタフェースを実装するときに使用する。カンマ区切りで並べた複数のインタフェースを実装することができる。SampleClass s = new SampleClass();int[] numbers = new int[5]; // int型の配列を生成List<String> list = new ArrayList<>(); // ジェネリッククラスのインスタンス化a instanceof ClassName とした場合、a が ClassName のオブジェクトか、その派生クラスのオブジェクトであれば true になる。ClassName の箇所にオブジェクトの変数名を記述することはできない。record Person(String name, int age) {
/* コンストラクタ、フィールド、アクセサメソッドは自動的に生成される */
}
public sealed class Shape permits Circle, Square {
// クラスの内容
}
public sealed class Shape permits Circle, Square {
// クラスの内容
}
public non-sealed class Circle extends Shape {
// クラスの内容
}
クラス、メンバの宣言に付けられる修飾子である。
publicでは、すべてのクラスからアクセスできる。protectedでは、同一パッケージにあるクラスかサブクラスからのみアクセスできる。異なるパッケージでサブクラスでないクラスからはアクセスできない。クラスを修飾することはできない (内部クラスは例外)。privateでは、他のクラスからはアクセスできず、自クラスからのみアクセスできる。クラスに修飾することはできない (内部クラスは例外)。private protectedという組み合わせを使用して、自分自身とサブクラスからのアクセスができるが同じパッケージ内の他のクラスからはアクセスできないというアクセス権を使用することができたが、これはJava SE 1.1以降から廃止され利用することができなくなった。例1:
public class SampleClass {
final int constantValue = 5;
}
例2:
public class SampleClass {
final int constantValue; // 初期化なし
// コンストラクタ
public SampleClass() {
constantValue = 5; // 1回だけ代入できる。
}
}
記述例:
class SampleClass {
static String shared = "shared";
static final String STR = "constant";
}
例:
class Sample1 {
// static なメソッド
public static void method() { ... }
}
class Sample2 {
void proc() {
...
Sample1.method(); // インスタンスを生成せず直接実行できる。
...
}
}
static {...}というブロックが現れた場合は、そのクラスが最初に参照されたときにそのブロック内のコードを実行する。これを静的初期化子と呼び、主にstatic finalな配列やCollectionオブジェクトの初期化などに利用される。データベースにアクセスするためにJDBCドライバを呼び出すClass.forName("ドライバ名")もこの静的初期化子を呼び出している。例:
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);
}
}
内部クラス
static修飾されていないものは内部クラス (inner class) と呼ばれ、暗黙的に外側のクラスのインスタンスをキャプチャして参照することができるが、このネストクラスをstatic修飾すると静的ネストクラス (static nested class) となり、暗黙的に外側のクラスのインスタンスを参照できなくなる。例:
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);
}
}
finalと併用することはできない。Javaでは、実装されないメソッドがあるクラスを作成することができる。抽象クラス自身のインスタンスを作成することはできない。似たものとしてインタフェースがあるが、abstract classは以下の点においてインタフェースと異なる。
abstract classはそのままではインスタンス化できず、不足しているメソッドを実装した派生クラスを用意して使用する。記述例:
public abstract class Sample {
// 実装があるメソッド
public void method1() {
...
}
// 実装がないメソッド
public abstract void method2();
}
記述例1:
public synchronized void method() { ... }
記述例2:
public void method() {
...
synchronized(this) { // 自クラスのインスタンスに対して排他制御
// 排他制御されるブロック
}
...
}
記述例3:
public void method(Object obj) {
...
synchronized(obj) { // Object obj に対して排他制御
// 排他制御されるブロック
}
...
}
例:
public class SampleClass {
volatile int syncSample;
...
}
C言語およびC++と共通のキーワードを使用している。
例外処理はC言語にはない。Javaでは、C++およびC#とほぼ共通の構文およびキーワードが使用されている。ただしfinallyはC++には存在せず、throwsはC#には存在しない。
try{と}との間) で例外が発生しうるコードを囲み、catchブロック (catch(Throwableの派生クラス例外オブジェクト){と}との間) に例外発生後の処理を書く。finallyブロック (finally{と}との間) には、ファイルのクローズ、データベースセッションの切断、ログアウトなど、例外発生の有無にかかわらずtry/catchブロック内の処理を終了する前に必ず実行しておきたいコードを書く。catchを記述した場合finallyは省略可能であり、finallyを記述した場合catchは省略可能である。try/catchブロックとfinallyブロックの両方にreturn文がある場合、後者が優先される。catchブロックにはif-else-if文のように連続して捕捉したい例外を記述することができる。throwsの明示が必要なRuntimeExceptionを継承していない例外throwsの明示が必要でないRuntimeExceptionを継承している例外以下はIOExceptionを使った記述例である。
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文が優先される。
...
}
}
AssertionError を投げる。浮動小数点演算の移植性を高めるstrictfpがある。浮動小数点の演算では一般に全く同じ結果は期待できないものではあるが、x87などハードウェアによっては、途中の値においてより高い精度や、より広い値の範囲で演算が行われるために、最終結果が他のプラットフォームと一致しない場合があり、特にIEEE 754を前提として予想される結果から外れることが問題である。
strictfpを指定すると、途中結果についても全てIEEE 754の倍精度を強制し、相異なるプラットフォーム同士の間でも演算結果が一致することを保証するとされている(仕様では FP-strict という用語を使っている)。Java VMの実装で、これを正しく実現するには、x86系CPUを使った計算機の場合、x87を避けてSSE2で計算するか、それができない場合は特殊なテクニックが必要である。
なお、同様に移植性のある結果を保証するStrictMathというクラスがあるが、そちらはFDLIBMというSun製のライブラリと同じ結果を保証するとされている。
Java 17以降は常にstrictfpを付けたときの挙動と同じになった。x86系CPUでは常にSSE2以降を使用して計算する。
const、gotoがキーワードとして予約されているが、Javaでは使用できない。使用するとコンパイル時に構文エラーになる。