Java プラットフォームで動作する Groovy を使ってクロスプラットフォーム GUI アプリの Hello World

# Groovy とは

Java 上で動作するスクリプト言語のこと。
Java に必要な機能を追加した結果とのこと。


## Groovy クイックインストール

### Windows の場合
1. 無ければ JDK (Java SE Development Kit) をインストールする。
1. [groovyのサイト](http://groovy-lang.org/) からインストーラをダウンロードする。
   記載当時 Groovy 2.4 が最新の安定版だった。
1. インストーラを実行する。
1. もし Groovy の環境変数が PATH に見つからない場合は追加する。（アンインストーラはこの情報を削除しない）
   JAVA_HOME が未設定だと警告が出る。これがないと Groovy が正常に動作しない。
   もし警告が出たら JDK をインストールしていない可能性があるので確認すること。
1. スタートメニューに「Start GroovyConsole」が表示されたらインストール完了。

## Hello Groovy World

1. Start GroovyConsole を起動する。
2. 画面上部（スクリプト記述エリア）に次のスクリプトを記載する。
`println("HelloWorld");`
3. **Execute GroovyScript**ボタンを押すか、**Ctrl+R**を押してスクリプトを実行する。
4. 画面下部に実行結果として*HelloWorld*が表示されたら成功。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/206493/9f7dbbdf-636e-cde7-360b-300160565ff5.png)

GUI（AWTのFrame）も試してみる。下記はHelloGroovyWorld(AWT)の実行画面。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/206493/a0734a20-5789-2475-4e64-25cf66762f81.png)

```groovy:例）HelloGroovyWorld(AWT)
/* Hello World (GUI) スクリプト */
import java.awt.*;
import java.awt.event.*;

/**
 * MainFrame クラス
 */
class MainFrame extends Frame
{
  def _menuBar;
  def _labelBody;

 /**
  * コンストラクタ
  */
  MainFrame() {

    /* タイトルを初期化 */
    setTitle("Hello World")

    /* メニューを初期化 */
    _menuBar = new MenuBar();
    def _menu = new Menu("ファイル");
    def _menuItem = new MenuItem("閉じる");
    _menuItem.addActionListener(new java.awt.event.ActionListener()
    {
        public void actionPerformed(ActionEvent e) {
            closeFrame(e);
        }
    });
    _menu.add(_menuItem);
    _menuBar.add(_menu);
    setMenuBar(_menuBar);

    /* フレーム内表示コンテンツを初期化 */
    _labelBody = new Label("Hello World");
    this.add(_labelBody);

    /* サイズを初期化 */
    setSize(new Dimension(300, 200));
  }

  /* フレームクローズ操作 */
  def closeFrame(e)
  {
    this.dispose();
  }
}

/* エントリポイント */
new MainFrame().show();
```


### Java に対する Groovy の特徴

参考情報：[Apache Groovy - Differences with Java](http://groovy-lang.org/differences.html)
参考情報：[Code Zine - Groovyってどんな言語？
JavaプログラマのためのGroovy入門](https://codezine.jp/article/detail/3757)


- 一般的に利用する機会の多いクラスパッケージのいくつかがデフォルトでimportされているため宣言せず利用できる。
  - java.io.\*, java.lang.\*, java.math.BigDecimal, java.math.BigInteger, java.net.\*, java.util.\*, groovy.lang.\*, groovy.util.\*
- マルチメソッド（又はランタイムディスパッチ）により、メソッド名と返値の型が同一で、引数の型が異なるメソッドが定義できる。これらは、実行時に与えた引数の型に応じて実行するメソッドが選択される。※どういったケースで便利なのかいまいち分からない。
- クロージャが使える。
  - クロージャは引数を取ることが出来る。引数は暗黙的に仮引数**it**で表される。明示的に指定することも可能。`clodure = { println("${it}が渡された。"); }; clodure("テスト");`、`clodure = { name,age -> println("${name}は${age}才です。"); }; clodure("Alice",10);`
  - クロージャは引数として指定できる。そのため each メソッドなどの引数に与えることで、制御構文を使わず配列の全要素へのアクセスが簡単に記述できる。`sum = 0; (1..10).each { sum += it }; println(sum);`
  - クロージャは宣言されたクラスの変数へアクセスできる。そのため、イベント駆動動作を容易に定義できる。
- 配列の初期化書式が異なる。（クロージャにより {} が予約されているため）`int[] array = [1,2,3];`
- 変数定義時のアクセス制御子を省略した際は private フィールドと認識され、Getter/Setter が自動定義される。また、パッケージ内で有効な package-private として定義する場合は、@PackageScope を記載する。（private と書かれているが、アクセス制御されていない様子）
  - Getter/Setter のメソッド名は `getXXX()`, `setXXX()` となる。※コンパイル時に自分が宣言していないメソッド名でエラーとなる場合はこの動作が原因である可能性がある。
- Automatic Resource Management (ARM) は使えない。同等の処理はクロージャを使って処理できる。`new File('C:\\path\\to\\file.txt').eachLine('Shift-JIS'){ println it; }`
- 匿名内部クラスの動作は Java の指針に従うものの挙動は異なる。詳細は Groovy の Documentation を参照のこと。
- Java 8 で定義されたラムダ式は匿名内部クラスとして認識できるが、Groovy ではシンタックスエラーとなる。代わりにクロージャを使うこと。
- ダブルクオートで括られた文字列リテラルは GString 型の値として処理される。
- シングルクオートで括られた文字列リテラルは明示的に char で宣言されない限り String 型として処理される。2 文字以上の文字列を char としてキャストすると最初の 1 文字だけの char として処理される。
- データ型は Object として認識され、プリミティブ型等へのオートラップされるため、widening/narrowing 変換処理の結果と異なることがある。
- 比較演算子 `==` の挙動が Java ではプロミティブ型の比較だが、Groovy では `a.compareTo(b)==0` または `a.equals(b)` に置き換えられる。同一性を確認するためには `a.is(b)` を使う。
- Groovy における暗黙の型変換の挙動は Java と異なる。詳細はGroovy の Documentation を参照のこと。 
- 他、**as**, **def**, **in**, **trait** がある。（予約文字）

- Java と比べてソースコードの記述ルールが緩い（Strictの逆）。例えば、行末のコロンは不要であり、データ型を宣言しなくてよい。また、どのクラスにも属さない文を記述することができる。（ルーズステートメント）
- def で変数を宣言すると、変数に代入された値に応じた適切な型を動的に変更する。
- マップ型が利用できる。`map = ["Alice":10, "Bob":20, "Charlie":30]; println(map["Alice"]);`
- 制御構文では暗黙で評価結果が 0 や null ならば false、他は true となる。
- switch文は数値以外を評価してcase分けできる。
- for文の書式が異なる。`for (m in list) { print m.toString(); };`
- クラス定義の動的変更（Expando）機能が用意されている。`def e = new Expando(); e.msg = "Hello World"; e.show = { println(msg); }; e.show();`
- java.sql パッケージにより SQL クエリ処理が楽に記述できる。
- Builder により HTML/XML/Swing 等の構造化されたデータが簡単に記述できる。`import groovy.xml.MarkupBuilder; new MarkupBuilder().html { body { div { mkp.yield( 'Hello World' ) }; div( style:'style.css' ) { mkp.yield('Groovy') } } }`