LoginSignup
6
11

More than 5 years have passed since last update.

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

Posted at

概要

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が投げられます。
例えば、メソッドの引数の値が想定通りの値かどうかをチェックするなどの用途で使用できます。

// 割り算
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を使用します。

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

default

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

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

switch文の例

switch(i) {
    case 1:
        System.out.println("一");
        break;
    case 2:
        System.out.println("二");
        break;
    default:
        System.out.println("その他");
}

アノテーションの例

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

    int min() default Integer.MIN_VALUE;

    int max() default Integer.MAX_VALUE;
}

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

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

goto

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

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

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

native

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

public native boolean createDirectory(File f);

strictfp

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

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

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

transient

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

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

volatile

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

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

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で修飾しないと想定通りに動作しない可能性があります。

…そのはずだったのですが、実際試したらvolatileなしでも普通に動きました。誰か詳しい人教えてください!

_(underscore)

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

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で追加されました。一つ一つ取り上げていると長くなるし私もよく把握できていないので説明は省略します。
いずれも特別な意味を持つ言葉ですが、変数名などとして使うことが可能です。おそらく、互換性のためでしょうね。

String module = "module";

予約された型名(reserved type name)

var

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

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

6
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
11