【じゃんけんゲームで入門】Java

当記事では、自作したじゃんけんゲームを題材にしてJavaの文法や使用するときの注意点などを確認していきます。Windows 10 Home 64bit版環境で検証しています。

ソースコードは以下よりご確認ください。

[rps-like/Java at master · tomomoss/rps-like](https://github.com/tomomoss/rps-like/tree/master/Java)

## じゃんけんゲームとは

じゃんけんゲームはコンソール上で動作するCUIゲームです。

基本的なルールは既存のじゃんけんそのものです。じゃんけんで勝つごとに1点取得し、対戦相手よりも先に5点先取することで勝者となります。

対戦内容はログファイルに書き出して、後から読み返せるようにします。

## Javaとは

Javaは、かつて存在していた米国のIT企業Sun Microsystems（現・Oracle America）によって開発されたプログラミング言語です。1996年1月にJDK 1.0が発表されて以来、継続的にバージョンアップを重ねてきています。当記事執筆時点での最新バージョンは2021年3月16日にリリースされたJava 16です。

言語の出自を辿ると、元々はC++をベースにした家電製品向け組み込み言語として開発が始まったようです。ただ、開発途中で組み込み対象が家電製品からPDAにシフトしたり、Web開発向けの言語としての側面なども持つようになりました。このように色々な分野に手を出してきたためか、今日では幅広い業界で使用される汎用性に優れた言語として成長しました。

20年以上にわたり第一線で活躍し続けてきた実績によって大きな信頼を築き上げてきたJavaですが、Javaよりも洗練されたJVM言語が台頭してきたり、Javaが有償化されるという誤解が広まったことで、その人気に冷や水を浴びせられた感は否めません。

とはいえ、今なお需要は全言語中でもトップクラスであり、仮に新規開発案件の選択肢から外れるような事態になってもJavaで書かれたシステムの保守改修案件は残るでしょうから、今後とも数十年というスパンで使われ続けるのは間違いありません。

## 開発環境構築手順

Javaで開発を行うには「JDK（Java Development Kit）」と呼ばれるプログラム群が必要です。JDKのなかにはJava製プログラムを実行するのに不可欠なJVM（Java Virtual Machine）やライブラリ、それにコンパイラなどが入っています。

このJDKを直接ダウンロード・インストールするか、あるいはJDKをプラグインとして導入できるIDE（EclipseとIntelliJ IDEAの2つが有名ですね）を使用して開発することになります。

余談ですがJDKはちょっと面白い開発体制になっていまして、Oracle・Intel・Red Hat・Googleといった世界中の名だたる大企業が改良やバグ修正に関わるOSSとして成立しています。そして、このJDKを元に様々な団体が独自に改修を加えたJDKも存在しています。それら独自改修型JDKと区別するために本家JDKは「OpenJDK」と呼ばれています。

じゃんけんゲーム制作にあたっては、このOpenJDK（厳密には「OpenJDK v16.0.1」）を使っています。

### OpenJDKをダウンロード

まずはOpenJDKをダウンロードしましょう。OpenJDKのサイトに向かいます。

[OpenJDK](https://openjdk.java.net/)

サイト中央に「What is this?」「Download」「Learn how to use the JDK」「Hack on the JDK itself」という4つの項目が並んでいるかと思います。この内Downloadの文中にあるリンクをクリックしてOpenJDKの最新バージョンのダウンロードページに飛んでください。当記事執筆時点ですと16.0.1が最新バージョンでした。

[JDK 16.0.1 GA Release](https://jdk.java.net/16/)

Linux・macOS・Windows、それぞれのOS向けのバイナリが用意されていますので、ご自身のOSに合わせたものをダウンロードしてください。今回はWindows向けのバイナリを選択します。

### OpenJDKを配置

ダウンロードした.zipファイルを解凍して、ファイル内に格納されたディレクトリ（「jdk-16.0.1」といった感じの名前になっているかと思います）を適当な場所に配置してください。私はドライブ直下に配置するようにしています。

### PATHを通す

OpenJDKが配置できましたら、ディレクトリ直下にある「bin」ディレクトリにPATHを通してください。また、新たに環境変数「JAVA_HOME」を登録し、OpenJDKが入っているディレクトリまでのパスを設定してください。

詳しくは以下記事を参考にしてください。

[JAVA_HOMEとPath - Qiita](https://qiita.com/Terry3/items/606c4554eabecf9010f1)

### 動作確認

動作確認をしましょう。適当なシェルを開いて以下コマンドを叩いてみてください。

```
PS C:\Users\tomomoss> java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment (build 16.0.1+9-24)
OpenJDK 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)

PS C:\Users\tomomoss> javac -version
javac 16.0.1
```

正常に応答したら問題ありません。

## 注意したい仕様

基本的な文法などはGitHubに上げているソースコードを読んでいただくか、あるいは自前で調べていただくとして――ここからは、GitHubに上げているソースコードからは読み取れない仕様や初めてJavaを触る人に向けての注意事項を列挙します。

### Javaの動かし方

Javaのソースファイルには「.java」拡張子を付けてください。

ソースファイルが用意できましたらコンパイルして **中間ファイル（.classファイル）** というファイルを生成します。コンパイラはjavac.exeというファイルになります。

```
PS C:\Users\tomomoss> javac .\Main.java
```

このとき、コンパイルしたソースファイルに格納されたクラスごとに中間ファイルが生成されます。たとえば、「Main.java」というソースファイルのなかに「Main」「Sub1」「Sub2」という3つのクラスが定義されていた場合「Main.class」「Sub1.class」「Sub2.class」という3つの中間ファイルが生成されます。

中間ファイルが生成されましたらjava.exeを使って実行します。このときjava.exeの第1引数に動作させたい中間ファイルを指定してください。また、中間ファイルの拡張子は記述しないでください。

```
PS C:\Users\tomomoss> java Main
```

Javaのコンパイルと実行の手順はちょっとややこしいので、必要に応じて様々な解説記事を参考にしてください。

### 文字コード

開発環境ごとに異なるようなのですが、Windows版OpenJDKの文字コードは標準で「 **MS932** 」という聞き慣れないものが使われているようです。またの名を「windows-31j」とも言い、Shift JISを拡張した文字コードらしいです。つまるところ、ソースコードに日本語を含まない場合はShift JISかUTF-8、ソースコードに日本語を含む場合はShift JISで記述することになります。

なお、導入した環境の標準文字コードは以下プログラムで確認できます。

```java
class Main {
  public static void main(String[] args) {
    System.out.println(System.getProperty("file.encoding"));
  }
}
```

ところで、Javaはコンパイル時に文字コードを指定することができます。

```
PS C:\Users\tomomoss> javac -encoding 文字コード コンパイルするソースファイル
```

私がそうなのですが、やはり文字コードにはUTF-8を使いたいものです。そういった方は以下コマンドを参考にしてください。

```
PS C:\Users\tomomoss> javac -encoding UTF-8 .\Main.java
```

### エントリポイント

Javaのエントリポイントはmainメソッドです。

当該メソッドを格納するクラス名は何でもかまいません。ただし、public修飾子を別の修飾子に変更したり、static修飾子を外したりと書式を変更するとエントリポイントとして認識されなくなりますので注意してください。

```java
class 適当なクラス名 {
  public static void main(String[] args) {
    // ※色々な処理
  }
}
```

### 全ての処理はいずれかのクラスに収める

クラスの使用が任意の言語や、そもそもクラスがない言語などとは異なり、Javaでは全ての処理をいずれかのクラス内に格納する必要があります。先述のように、エントリポイントとなるmainメソッドも例外ではありません。

### ==演算子とequalsメソッド

値が等しいかを判定するための方法として、==演算子とequalsメソッドの2つが用意されています。前者は同一のものであるか、後者は同じ値であるかを判定するための機能です。

以下コードをご覧ください。

```java:Test.java
class Test {
  public static void main(String[] args) {

    // 同じ値のStringBuilderオブジェクトを2つ生成します。
    StringBuilder a = new StringBuilder("Hello world.");
    StringBuilder b = new StringBuilder("Hello world.");

    // ==演算子で判定します。
    System.out.println(a.toString() == b.toString());

    // equalsメソッドで判定します。
    System.out.println(a.toString().equals(b.toString()));
  }
}
```

```
PS C:\Users\tomomoss> Test.java

PS C:\Users\tomomoss> java Test
false
true
```

どちらも同じ値を持つStringBuilderオブジェクトですが **==演算子で判定した場合とequalsメソッドで判定した場合で真偽が異なりました** 。equalsメソッドが真だと判定したのは同じ値だからです。==演算子が偽だと判断したのは異なるオブジェクトだからです。

### 戻り値があるメソッドでは、全ての条件分岐でreturnが必要

JavaにはSystem.exitというメソッドがあります。これはJava製プログラムを動かすJVMの動作を停止させる命令文です。

これを踏まえたうえで以下コードをご覧ください。

```java:Test.java
class Test {
  public static void main(String[] args) {
    System.out.println(sampleMethod("a"));
  }

  /**
   * 引数に応じた文字列を返します。
   * 不適当な文字列が指定された場合はSystem.exitメソッドでJVMを停止させます。
   */
  private static String sampleMethod(String foo) {

    // 想定された値であれば対応する文字列を返します。
    if (foo.equals("a")) {
      return "aです。";
    }
    if (foo.equals("b")) {
      return "bです。";
    }
    if (foo.equals("c")) {
      return "cです。";
    }

    // 想定されていない場合はJVMを止めます。
    System.exit(0);
  }
}
```

一見すると、このプログラムには問題がないように見えるかもしれません。しかし、実際にはコンパイルできずに構文エラーとして弾かれます。「return文が指定されていません」とのことです。

```
PS C:\Users\tomomoss> javac .\Test.java
.\Test.java:25: エラー: return文が指定されていません
  }
  ^
エラー1個
```

Javaでは、メソッドが戻り値を返すときは **発生しうる分岐の全てでreturn文が書かれていなければならない** ようです。

上記ソースコードの場合、以下のように修正するとコンパイルできるようになります。

```java
class Test {
  public static void main(String[] args) {
    System.out.println(sampleMethod("a"));
  }

  /**
   * 引数に応じた文字列を返します。
   * 不適当な文字列が指定された場合はSystem.exitメソッドでJVMを停止させます。
   */
  private static String sampleMethod(String foo) {
    if (foo.equals("a")) {
      return "aです。";
    }
    if (foo.equals("b")) {
      return "bです。";
    }
    if (foo.equals("c")) {
      return "cです。";
    }
    System.exit(0);

    // 仕様上必要なためにreturn文を置いています。
    return "";
  }
}
```

## 私が意識していること

Javaを使うときに私が意識していることを列挙します。1つ前の「注意したい仕様」を読んでいることを前提とした内容になっています。

### コーディング規約

Javaの公式コーディング規約（Sun Microsystems製コーディング規約、あるいはOracle製コーディング規約）はないようです。

その代わりに様々な団体からコーディング規約が発表されていますので、いずれかのコーディング規約を参考にするのが良いのではないでしょうか。