意外と知らない、Javaの予約語まとめ

# 概要
Javaの予約語は、頻繁に見かけるものからあまり見かけないものまで、色々あります。
私の独断と偏見で選んだ、あまり見かけない予約語について簡単に紹介します。

あまり長くならないように、一つ一つに対してそれほど詳細な話はしません。

なお、Javaの言語仕様上「予約語」は「キーワード(keyword)」と呼ばれるそうですが、
「予約語」のほうが一般的な気がするので、この記事では「予約語」という呼称を使用します

# 対象読者
Java初心者
Javaをある程度使いこなしている方にとっては既知の内容になるかもしれません（予防線）

# 環境
Java11

# Javaの予約語一覧
まずは予約語の一覧を見てみます。公式の言語仕様書によると、Java11時点で予約語は下記の通り51個あります。
https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.9

```
abstract   continue   for          new         switch
assert     default    if           package     synchronized
boolean    do         goto         private     this
break      double     implements   protected   throw
byte       else       import       public      throws
case       enum       instanceof   return      transient
catch      extends    int          short       try
char       final      interface    static      void
class      finally    long         strictfp    volatile
const      float      native       super       while
_ (underscore)
```

この中からいくつかピックアップして紹介してみます。

# 予約語（keyword）
## assert
Javaで表明（assertion）を使うための予約語です。
表明とはプログラムを実行する際に満たされているべき前提条件を記述するもので、誤解を恐れずに言えば変数の値が想定外の値になっていないかどうか等をチェックする仕組みのようなものです。

assertの後に条件式を書き、条件式の評価値がfalseだったらAssertionErrorが投げられます。
例えば、メソッドの引数の値が想定通りの値かどうかをチェックするなどの用途で使用できます。

```java
// 割り算
private int divide(int x, int y) {
    assert y != 0;  // 割り算なのでyは0であってはならない

    return x / y;
}
```
また、assertは実行時に-enableassertions（または-ea）を指定しないと有効になりません。
上記オプションを渡すかどうかで、有効無効を切り替えられます。
開発中は有効にして、本番稼働時は無効にするといったことが可能です。

## const
C言語などでは定数を宣言するための予約語ですが、Javaでは何の意味も持たない予約語です。
何の意味もないのに、なぜか予約語としては存在しています。
constは構文上は何の意味も持たないため、使用するとコンパイルエラーになります。

なお、Javaで定数を宣言するにはconstではなくfinalを使用します。

```java
// 予約語なのでシンタックスハイライトはされる
const int num = 1;
//  エラー:
//  式の開始が不正です
//  const int num = 1;
//  ^
```

## default
複数の用途がある珍しい予約語です。バージョンが上がるにつれて追加されていきました。

- switch文で、合致する項目がなかった場合に実行される箇所を示すラベル
- アノテーションの定義で、定数のデフォルト値を指定する修飾子（Java 5から）
- インタフェースの定義で、デフォルトメソッドであることを示す修飾子（Java 8から）

switch文の例

```java
switch(i) {
    case 1:
        System.out.println("一");
        break;
    case 2:
        System.out.println("二");
        break;
    default:
        System.out.println("その他");
}
```
アノテーションの例

```java
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Range {

    int min() default Integer.MIN_VALUE;

    int max() default Integer.MAX_VALUE;
}
```

インタフェースのデフォルトメソッドの例

```java
public interface Person {
    default String name() {
        return "unknown";
    }
}
```

## goto
C言語などでは任意の箇所に制御を飛ばすのに使用する予約語ですが、const同様にJavaでは何の意味もないのに存在している予約語です。
gotoに相当する機能はJavaにはありません。gotoを乱用するとソースコードの可読性が著しく下がるため、比較的モダンな言語では同等の機能が存在しないことが多いです。

constと同様、使用するともちろんコンパイルエラーです。

```java
// やはりシンタックスハイライトはされる
goto label;
//  エラー:
//  式の開始が不正です
//  goto label;
//  ^
```

## native
メソッドの中身がC言語などのネイティブ言語で実装されていることを示す予約語です。
JNIなどを使って実行されます。

```java
public native boolean createDirectory(File f);
```

## strictfp
浮動小数点の計算結果が、実行環境に依存して変化しないようにする（どの実行環境でも同じ結果になるようにする）ための予約語です。
メソッドやクラスを修飾します。
逆に言えば、strictfpで修飾しない場合は浮動小数点の計算結果は実行環境によって変わる場合があるということです。

個人的には、実際に使われているのを一度も見たことがありません。

```java
private strictfp double calc(double x, double y) {
    return x * y;
}
```

## transient
修飾したフィールドがシリアライズの対象外になります。
シリアライズとは、オブジェクトの内容をファイルに保存したり、他のマシンに送信したりできるように変換を行うことです。
transientで修飾することで、シリアライズ後のデータから該当のフィールドが除外されます。

```java
public class Person implements Serializable {
    private String firstName;
    private String lastName;
    private transient String fullName;
}
```

## volatile
修飾したフィールドについて、シングルスレッド前提の最適化を抑止します。
見たことはあるが、どういう意味があるのかわからないという方もいらっしゃると思います。

私もよくわかりません。


volatileで修飾しない場合、コンパイラが最適化のためにソースと若干違う内容のバイトコードを出力することがありますが、volatileによってそのような最適化が抑止されます。
シングルスレッドの場合は特に影響ありませんが、マルチスレッドだとコンパイラによる最適化によって不整合が生じる場合があります。volatileはそのような不整合の発生を防ぐのに使われます。

```java
volatile boolean shutdownRequested;
 
...
 
public void shutdown() { shutdownRequested = true; }
 
public void doWork() { 
    while (!shutdownRequested) { 
        // do stuff
    }
}
```
https://www.ibm.com/developerworks/jp/java/library/j-jtp06197.html より

上記例では、shutdown()が他のスレッドから呼ばれたらループを抜けるという動作を期待していますが、shutdownRequestedをvolatileで修飾しないと想定通りに動作しない可能性があります。

<font color="Lavender">…そのはずだったのですが、実際試したらvolatileなしでも普通に動きました。誰か詳しい人教えてください！</font>

## _(underscore)
Scalaなどの言語では、_はプレースホルダ等の用途で使用しますが、Javaにはそのような機能はありません。const、gotoと同様に意味のない予約語（記号？）です。
_が予約語になったのはJava9と比較的最近で、将来の機能拡張を見据えてのことなのかもしれません。

```java
int _ = 1;
//  エラー:
//  リリース9から'_'はキーワードなので識別子として使用することはできません
//  int _ = 1;
//      ^
```

# 番外編

## かつて存在した予約語
### widefp
strictfpの逆で、浮動小数点の計算結果が環境に依存するようになります。
現在は既定でそのような動作であるため、widefpは削除されました。


## 予約語っぽいけど予約語じゃないもの
### リテラル
#### true および false
おなじみのbooleanリテラルです。実はこれらはJavaの言語仕様上は予約語ではないのです。
まあ、識別子としては使えないので実質予約語みたいなものですけどね。

#### null
おなじみのnullリテラルです。これもbooleanリテラルと同様に、識別子としては使えませんが、言語仕様上は予約語ではありません。

### 制限されたキーワード （restricted keyword）
#### open, module, requires, transitive, exports, opens, to, uses, provides, with
いずれもモジュール機能のためにJava9で追加されました。一つ一つ取り上げていると長くなる
し私もよく把握できていない
ので説明は省略します。
いずれも特別な意味を持つ言葉ですが、変数名などとして使うことが可能です。おそらく、互換性のためでしょうね。

```java
String module = "module";
```

### 予約された型名（reserved type name）
#### var
Java10から追加された型推論機能のために使われます。
これも上記の「制限されたキーワード」と同様、特別な意味を持ちますが変数名などとして使うことが可能です。これも互換性のために予約語としていないのかもしれません。

```java
var var = 1;
```

# まとめ
Javaの予約語から、予約語っぽいけど予約語じゃないものまで、いろいろ見てきました。
そんなのあったんだ、と思ってもらえたらうれしいです。

# 参考リンク
https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.9
https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89_(Java)
https://java.keicode.com/lang/assert.php
https://www.wdic.org/w/TECH/strictfp
https://www.ibm.com/developerworks/jp/java/library/j-jtp06197.html
https://www.wdic.org/w/TECH/%E4%BA%88%E7%B4%84%E8%AA%9E%20%28Java%29