No Programming, No Life

新しいNPNLです。http://d.hatena.ne.jp/fumokmm/ から引っ越してきました。

Groovy基礎文法最速マスター

Groovyリファレンス系記事の一覧はこちら

Groovyの基礎文法最速マスターが無かったようなので書いてみました。

0. はじめに

GroovyはJavaのシンタクスシュガーな上位互換として設計されており、妥当なJavaプログラムであれば、ほぼそのままでGroovyプログラムとして動かすことができます。*1
誤解を恐れずに言うならば、現存するプログラミング言語中でもっともJavaと親和性の高いBetter Javaな言語、それがGroovyであるということです*2。Groovyを利用すれば世界中に存在する有益なJava資産をすべて利用することができます。また、スクリプトとしてではなく.classファイルにコンパイルすることも可能です。コンパイルすることで通常のJavaプログラムと同等の動作スピードを得ることができます。

1. 基礎

Groovyの実行 *3
コマンド 説明
groovysh Groovyコードを対話的に実行するためのコマンドラインシェルを起動します。文やスクリプトを1行ごとに入力しコードをその場で実行することができます。
groovyConsole Groovyコードを対話的に実行するためのグラフィカルインタフェースを起動します。GroovyConsoleはGroovyスクリプトファイルをロードして実行することもできます。
groovy Groovyスクリプトを実行するインタプリタを起動します。コマンドライン引数として1行だけのGroovyスクリプトを指定することもできます。
表示 (print, println, printf)
print 'Hello, Groovy!!'        // 改行なし
println 'Hello, Groovy!!'      // 改行あり
printf 'Hello, %s', 'Groovy!!' // 整形して表示
コメント *4
// 一行コメント
/* 複数行コメント */
/** Groovydoc(Javadoc)コメント */

Groovydocについてはこちら

括弧やセミコロンの省略 *5

Groovyではコードの解釈に支障がない場合に限り、括弧やセミコロンの省略が可能です。

println("hi");
println("hi")
println "hi"

上記はすべて同じ意味となります。

アサーション *6

Groovyではどこでもassert文を利用できます。コード内にassertテストを埋め込んでコードの正当性を保つのがGroovyのスタイルです。

assert 式, コメント

上記のような形式で利用できコメントは省略可能です。

def a = 10
def b = 20
assert 30 == a + b, '足したら30のはず'

式が真の間は実行しても何も起こりませんが、偽の場合はエラーとなります。assert文が文に埋め込まれているおかげで、その時点での変数などの状態の正当性が主張できるわけです。以降、サンプルコードでもassert文を利用します。

等値性と同一性

#equals()は==, ==は #is() *7
Javaと比較すると以下のようになります。

Groovy Java
等値性 a == b a.equals(b)
同一性 a.is(b) a == b

また、nullに対してもチェック可能です。

assert null == null
assert !(null == 1)

2. データ型

すべてがObject(プリミティブはない)

1, 1.0fなどのJavaでのプリミティブはjava.lang.Integerや、java.lang.Floatなどのラッパーでラッピングされているため、通常のリテラルのように利用することが可能となります。

数値型リテラル *8

数値型リテラルとして利用できるのは以下です。

エイリアス リテラル
java.lang.Integer int 15, 0x1234ffff
java.lang.Long long 100L, 200l*9
java.lang.Float float 1.23f, 4.56F
java.lang.Double double 15, 0x1234ffff
java.lang.BigInteger - 123g, 456G
java.lang.BigDecimal - 1.23, 4.56, 1.4E4, 2.8e4, 1.23g, 1.23G
def (型の指定) *10

defキーワードはどんな型でもよいということを示すために使われます。
明示的に型を指定してもよい。

def a = 1      // => 実際の型はjava.lang.Integer (暗黙の型付け)
def b = 1.0f   // => 実際の型はjava.lang.Float   (暗黙の型付け)
int c = 1      // => 実際の型はjava.lang.Integer (Javaの基本型を使った明示的な型付け)
float d = 1    // => 実際の型はjava.lang.Float   (Javaの基本型を使った明示的な型付け)
Integer e = 1  // => 実際の型はjava.lang.Integer (参照型の型名を使った明示的な型付け)
String f = '1' // => 実際の型はjava.lang.String  (参照型の型名を使った明示的な型付け)

intやfloatなどはjava.lang.Integerやjava.lang.Floatのエイリアスです。

演算子のオーバーライド *11

たとえば、1 + 1 は 1.plus(1) の便利な書き方に過ぎません。これはIntegerクラスがplusメソッドの実装を持つことによって実現されています。これは他の演算子についても可能で自作クラスにも適用できます。Javaと違って特定のインタフェース実装は必要ありません。主な例を示します。


























演算子名前メソッド
a + b加算a.plus(b)
a - b減算a.minus(b)
a * b乗算a.multiply(b)
a / b除算a.div(b)
a % b剰余a.mod(b)
a ** bべき乗a.power(b)
a << b左シフトa.leftShift(b)
a >> b右シフトa.rightShift(b)
a >>> b論理右シフトa.rightShiftUnsigned(b)
a & bビット積a.and(b)
a | bビット和a.or(b)
a ^ b排他的ビット和a.xor(b)
a == b, a != b等値判定a.equals(b)*12
a < b, a > b,
a <= b, a >= b,
a <=> b
大小比較a.compareTo(b)
a as b強制型変換a.asType(b)
a in b包含判定a.isCase(b)
a++, ++aインクリメントa.next()
a--, --aデクリメントa.previous()
+a単項プラスa.positive()
-a単項マイナスa.negative()
~aビット否定a.bigwiseNegate()
a[b]添字a.getAt(b)
a[b] = c添字代入a.putAt(b, c)

文字列 *13

文字列リテラルは3種類。
単一引用符を用いた場合、通常の文字列として扱われます。(java.lang.Stringと等価)

'単一引用符'

二重引用符で囲んだ場合は、以下のように変数($の後に変数名)や式を埋め込むことができます。

def a = 'world'
def str1 = "hello $a"
def str2 = "hello ${a}"
assert str1 == str2
assert str1 == 'hello world'

//を用いた場合、\がエスケープせずに利用できるため、正規表現を埋め込む際に利用されます。(それ以外は二重引用符と同様)

/^\d{4}-\d{3}/

また、複数行文字列*14リテラルレベルでサポートされています。二重引用符と単一引用符で利用可能です。*15

def multiStr1 = '''
これは
複数行の
文字列です。
'''
def multiStr2 = """
本日は
${new Date()}
なり。
"""

3. 文法

文は1行にひとつ書きます。セミコロン(;)を付けることで、1行に複数の文を記述することができます。

12
1; 文2

制御構造 *16

if-else
if (false) assert false // 単一行のif

if (null) {      // nullは偽
  assert false
} else {
  assert true
}
while
def i = 0
while (i < 10) {
  i++
}
assert i == 10
doはない

Groovyにdoはありません。*17

for
for (i = 0; i < 10; i++) { // 昔ながらのfor
  println i
}

def clinks = 0
for (remainingGuests in 0..9) { // 範囲に対するfor
  clinks += remainingGuests 
}

def list = [0, 1, 2, 3, 4, 5]
for (j in list) { // リストに対するfor
  assert j == list[j]
}
switch
switch(3) {
  case 1 : assert false; break
  case 3 : assert true;  break
  default: assert false
}
try-catch-finally
try {
  // 処理
} catch(e) {
  // 例外e発生時処理
} finally {
  // 最終処理
}
return/break/continue *18

return, break, continueの一般的なロジックはJavaと同じです。
ただし、Groovyではreturnが省略可能です。省略した場合、最後に評価された値が返却されます。

def method() {
  def a = 10
  def b = 20
  a + b
}
assert method() == 30
Booleanテスト(Groovy Truth) *19
実行時の真 判定される値 実行時の真 判定される値
Boolean 値がtrue String、GString 文字列が空ではない
Matcher マッチする Number、Character 値がゼロではない
Collection コレクションが空ではない 上記以外 参照がnullではない
Map マップが空ではない
// Boolean値は自明
assert true
assert !false

// Matcherはマッチすること
assert ('a' =~ /./)
assert !('a' =~ /b/)

// コレクションは空ではないこと
assert [1]
assert ![]

// マップは空ではないこと
assert ['a': 1]
assert ![:]

// 文字列は空ではないこと
assert 'a'
assert !''

// 数値(どの型も)はゼロではないこと
assert 1
assert 1.1
assert 1.2f
assert 1.3g
assert 2L
assert 3G
assert !0

// その他は、すべてnullではないこと
assert new Object()
assert !null
正規表現 *20

Groovyは言語レベルで正規表現をサポートしています。

assert '12345' =~ /\d+/
assert 'xxxxx' == '12345'.replaceAll(/\d/, 'x')

正規表現についてはここがとても参考になります。

リスト、マップ、範囲 *21

リストは[]で囲み、カンマで区切ります。

def roman = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII'] // ローマ数字のリスト
assert roman[4] == 'IV' // リストへのアクセス
roman[8] = 'VIII' // リストの拡大
assert roman.size() == 9

マップも[]で囲み、「キー:値」の形で内容を示し、カンマで区切ります。

def http = [
  100 : 'CONTINUE',
  200 : 'OK',
  400 : 'BAD REQUEST' ]
assert http[200] == 'OK'
http[500] = 'INTERNAL SERVER ERROR'
assert http.size() == 4

範囲は「a..b」や「a..

def x = 1..10
assert x.contains(5)
assert x.contains(15) == false
assert x.size() == 10
assert x.from == 1
assert x.to == 10
assert x.reverse() == 10..1
def y = 1..<10
assert y.from == 1
assert y.to == 9
クロージャ *22
[1, 2, 3].each { entry -> println entry }
[4, 5, 6].each { println it } // パラメータ省略時はitで参照できる
[a: 100, b: 200, c: 300].each { key, value ->
  println "${key}=${value}"
}

このあたりのもうちょっと詳しいサンプルはこのあたりでどうぞ。

4. クラス *23

暗黙的インポート

Groovyでは以下のパッケージが暗黙的にインポート済みです。

java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.* 
クラス宣言
class Book {    // クラスを宣言
  String title  // 型を明示的に指定してフィールドを宣言
  def prop      // defキーワードでフィールド宣言
  Book() {      // コンストラクタ
    // ...
  }
  int methodA(int p) { // 型を明示的に指定してメソッドを宣言
    // ...
  }
  void methodB(String p) { // 戻り値なしメソッド
    // ...
  }
  def methodC(p) { // defを使ってメソッドを宣言
    // ...
  }
  static def methodS() { // 静的メソッドを宣言
    // ...
  }
}
GroovyBean *24

GroovyではJavaよりも簡単にbeanを扱えます。

class Book {
  String title  // プロパティの宣言
}
def groovyBook = new Book()

// 明示的なメソッド呼び出しによるプロパティの利用
groovyBook.setTitle('Groovy world')
assert groovyBook.getTitle() == 'Groovy world'

// Groovyによるショートカットを使ったプロパティの利用
groovyBook.title = 'No Groovy, No Life'
assert groovyBook.title == 'No Groovy, No Life'

(まだまだ紹介しきれないので、ちょこちょこ追加していく予定です。)

おすすめリンク


Groovy JDK
Groovy JDK

参考書籍 [GinA]

Groovyイン・アクション

Groovyイン・アクション

更新履歴

*1:2011-02-12追記:参照 [http://d.hatena.ne.jp/fumokmm/20110212/1297522544:title]

*2:唯一の違いは拡張子が.javaではなく.groovyであることくらいです

*3:[GinA] P12

*4:[GinA] P26

*5:[GinA] P5, 27

*6:[GinA] P28

*7:[GinA]] P242, 394

*8:[GinA] P50

*9:「1」と混同しやすいので小文字のlは推奨されていない

*10:[GinA] P52

*11:[GinA] P54

*12:aがComparableを実装している場合は、 a.compareTo(b)

*13:[GinA] P58

*14:いわゆるヒアドキュメント。

*15:参考に、この例の書き方ですと、先頭に改行が入ってしまいます。改行がない状態で宣言したい場合は[http://d.hatena.ne.jp/fumokmm/20080830/1220063759:title=こちら]を参照ください。

*16:[GinA] P39

*17:[http://d.hatena.ne.jp/fumokmm/20110630/1309446463:title:bookmark] にて無理やりdo-whileを実装する実験をしました。

*18:[GinA] P143

*19:[GinA] P130

*20:[GinA] P34

*21:[GinA] P35

*22:[GinA] P37

*23:[GinA] P31

*24:[GinA] P33