Yasuharu Nakano / @nobeans
Java開発の強力な相棒として今すぐ使える
2015-04-11
JJUG CCC 2015 Spring #ccc_g6
中野 靖治
@nobeans
所属:NTTソフトウェア株式会社
Grails推進室
職業:Grails Advocate
概要
Groovyとは
Javaをもっとすごくしたもの
「ポストJava」ではなく「Java強化外骨格」もしくは
「Java拡張パック」のイメージ
Java VM上で動作する動的型付け言語
Rubyによく似た文法を持ち、生産性が高い
Groovy界隈はRubyへのリスペクト成分が高め
Grailsの旧名「Groovy on Rails」
2003年生まれ(平成生まれ)
in Java
//	
  HelloWorld.java	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello,	
  World!");	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  World!
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello,	
  World!");	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  World!
Groovyとしてもvalidなコードなので
拡張子を変えるだけでOK
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello,	
  World!");	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  World!
セミコロンは省略可能
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  System.out.println("Hello,	
  World!")	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  World!
Object#println()が使える(GDKのひとつ)
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  println("Hello,	
  World!")	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  World!
スクリプト形式で実行可能(クラスが不要)
in Groovy
//	
  HelloWorld.groovy	
  
println("Hello,	
  World!")	
  
//=>	
  Hello,	
  World!
メソッド呼び出しの丸括弧は省略可能
in Groovy
//	
  HelloWorld.groovy	
  
println	
  "Hello,	
  World!"	
  
//=>	
  Hello,	
  World!
動的型付け言語
Groovyは基本的に動的型付け言語
動的型付けの例
Integer	
  num	
  =	
  "Hello"	
  
//=>	
  GroovyCastException:	
  Cannot	
  cast	
  object	
  'Hello'	
  
with	
  class	
  'java.lang.String'	
  to	
  class	
  
'java.lang.Integer'
groovycでコンパイルには成功する
しかし、実行すると例外が発生する
静的型付けサポート
Groovy 2.0から静的型付けのための機能が追加
@TypeChecked
コンパイル時に静的に型チェックする
ただし、実行時は動的型付けのまま
@CompileStatic
静的にコンパイルする
実行時に動的型付けによる機構は使われない
Javaとほぼ同等レベルの性能に(理論上)
どちらもクラス単位、メソッド単位で指定できる
ただし、明示的な型指定が省略できない
動的を前提とした一部の機能も使えなくなる
http://beta.mybetabook.com/showpage/508402720cf2ffb79bb046db
Java言語との密な関係
Java(7以前)との文法の互換性が高い
Java開発者なら非常にとっつきやすい
ただし、Java 8のラムダ記法は未対応
代わりにクロージャを使う
すべてのJava APIがシームレスに呼び出せる
標準API、サードパーティのクラスもすべて普通に使える
更に「Groovy JDK(GDK)」と呼ばれる超便利メソッ
ド群が標準クラスに追加されている!
コンパイルするとclassファイルになる
最低限、Java VMとgroovy-all.jarだけあれば実行できる
Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
今日は後半でこの辺を中心に紹介します
Groovy入門
その前にまずは
Javaとの文法の違い
Javaとの文法の違い
セミコロンは省略可能
returnも省略可能
チェック例外のthrows宣言も省略可能
型宣言も省略可能
プリミティブ型はラッパー型
各種リテラル
数値/文字列/リスト/マップ
アクセス修飾子
メソッド呼び出し
セミコロンは省略可能
//	
  セミコロンは不要	
  
int	
  a	
  =	
  1	
  
//	
  セミコロンはあってもOKだが、付けない方がお勧め	
  
int	
  b	
  =	
  2;
returnも省略可能
String	
  hello()	
  {	
  
	
  	
  	
  	
  //	
  returnは省略できる	
  
	
  	
  	
  	
  //	
  Ruby等と同様に最後に評価された値が返る	
  
	
  	
  "Hello"	
  
}	
  
assert	
  hello()	
  ==	
  "Hello"
チェック例外のthrows宣言も省略可能
String	
  doWithoutThrows()	
  {	
  
	
  	
  	
  	
  throw	
  new	
  Exception("チェック例外!")	
  
}	
  
try	
  {	
  
	
  	
  	
  	
  doWithoutThrows()	
  
	
  	
  	
  	
  assert	
  false	
  
}	
  catch	
  (Exception	
  e)	
  {	
  
	
  	
  	
  	
  assert	
  e.getMessage()	
  ==	
  "チェック例外!"	
  
}
throwsがなくてもOK!
型宣言も省略可能
def	
  キーワード
Object型の別名として宣言時に使える



以下の場合、型宣言自体を省略可能(→Object型)
メソッドや変数で、privateやstaticなどの修飾子が1つ以上ある場合
メソッドの仮引数
final	
  helloPrefix	
  =	
  "Hello,	
  "	
  
public	
  hello(name)	
  {	
  
	
  	
  	
  def	
  message	
  =	
  helloPrefix	
  +	
  name	
  
	
  	
  	
  return	
  message	
  
}
省略はできるが、ドキュメンテーションとして考えると、公開APIのシグネチャで
は型を明記する方が好ましい
def	
  hoge	
  =	
  "ほげ"
プリミティブ型で宣言しても実体はラッパー型
ただし、nullは代入不可能
また、最適化機構により、可能な場合において内部的に
もプリミティブ型のまま扱われる場合もある
プリミティブ型はラッパー型
assert	
  1.getClass()	
  ==	
  java.lang.Integer	
  
double	
  d	
  =	
  1.0	
  
assert	
  d.getClass()	
  ==	
  java.lang.Double	
  
assert	
  true.getClass()	
  ==	
  java.lang.Boolean	
  
//	
  もちろんメソッドも呼べる	
  
assert	
  d.plus(2.5)	
  ==	
  3.5	
  
//	
  nullは代入不可能	
  
d	
  =	
  null	
  //=>	
  GroovyCastException:	
  Cannot	
  cast	
  object	
  'null'	
  
with	
  class	
  'null'	
  to	
  class	
  'double'.
リテラル:数値
Groovyの浮動小数リテラルはBigDecimal型
桁あふれや誤差を気にしないで演算できる
プリミティブ型のように通常の中置演算子が使える
assert	
  5.3.getClass()	
  ==	
  java.math.BigDecimal	
  
//	
  普通に中置演算子も使える	
  
assert	
  (1.0	
  /	
  3)	
  ==	
  0.3333333333	
  
assert	
  (1.0	
  /	
  3).getClass()	
  ==	
  java.math.BigDecimal	
  
//	
  Javaでは誤差が発生するが、GroovyはBigDecimalなので一致する	
  
assert	
  (1.0	
  -­‐	
  (1.0	
  /	
  3.0))	
  ==	
  (2.0	
  /	
  3.0)
#ccc_cd3 でBigDecimal話がありましたね
リテラル:文字列
//	
  基本はJavaと同じくダブルクォーテーション	
  
println	
  "Hello,	
  World!"	
  	
  //=>	
  Hello,	
  World!	
  
//	
  ${}によって変数を展開できる(紛らわしくなければ{}も省略できる)	
  
String	
  name	
  =	
  "World"	
  
assert	
  "Hello,	
  ${name}!"	
  ==	
  "Hello,	
  World!"	
  
//	
  厳密にはGString型のリテラル	
  
assert	
  "Hello,	
  ${name}!".getClass()	
  ==	
  
org.codehaus.groovy.runtime.GStringImpl	
  
//	
  純粋にString型が必要な場合はシングルクォーテーションを使う	
  
//	
  Javaではchar型リテラルだったが、Groovyではchar型リテラルは無し	
  
assert	
  'Hello,	
  ${name}!'	
  !=	
  "Hello,	
  World!"
リテラル:文字列
//	
  トリプル「ダブルクォート」(ややこしい)	
  
//	
  改行や単体のクォート文字列自体を含められる(GString型)	
  
//	
  トリプル「シングルクォート」にすると単なるString型になる(展開無し)	
  
def	
  s	
  =	
  "Third"	
  
println	
  """First,	
  
"Second",	
  
${s}.	
  
"""	
  
//=>	
  
//	
  First,	
  
//	
  "Second",	
  
//	
  Third.
ヒアドキュメント風に使える
リテラル:文字列
//	
  開始行の行末エスケープとString#stripMargin()を使うと、	
  
//	
  いい感じにインデントできて、読みやすい	
  
def	
  s	
  =	
  "Third"	
  
println	
  """	
  
	
  	
  	
  	
  |First,	
  
	
  	
  	
  	
  |"Second",	
  
	
  	
  	
  	
  |${s}.	
  
	
  	
  	
  	
  |""".stripMargin()	
  
//=>	
  
//	
  First,	
  
//	
  "Second",	
  
//	
  Third.
GDKのString#stripMargin()と合わせて使
うとインデントもいい感じにできる
リテラル:文字列
//	
  スラッシュクォート	
  
//	
  単体バックスラッシュを特殊文字として扱わないため、エスケープが不要。	
  
//	
  正規表現をシンプルに書ける	
  
assert	
  (/This	
  is	
  backslash	
  'n'/	
  ==	
  "This	
  is	
  backslash	
  'n'")	
  
assert	
  "Hello,	
  World!".matches(/Hello,s.*/)	
  
//	
  Pattern型ではなく、あくまでString型	
  
assert	
  (/Not	
  Pattern,	
  But	
  String/.getClass()	
  ==	
  String)	
  
//	
  丸括弧で囲まないとコンパイルエラーになるケースがあるので注意	
  
assert	
  /Naked	
  Slashed/	
  
	
  	
  	
  	
  //=>	
  "1	
  compilation	
  error:	
  unexpected	
  token:	
  /"
正規表現を書くときは断然コレ
リテラル:リスト
//	
  専用リテラルの導入により、シンプルにリストを記述できる	
  
def	
  l	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
assert	
  l.size()	
  ==	
  5	
  
assert	
  l.getClass()	
  ==	
  java.util.ArrayList	
  
//	
  空リスト	
  
assert	
  [].size()	
  ==	
  0	
  
//	
  要素へのアクセス	
  
assert	
  l[0]	
  ==	
  1	
  
assert	
  l[2..3]	
  ==	
  [3,	
  4]	
  
assert	
  l.first()	
  ==	
  1	
  
assert	
  l.last()	
  ==	
  5	
  
assert	
  l.head()	
  ==	
  1	
  
assert	
  l.tail()	
  ==	
  [2,	
  3,	
  4,	
  5]
(参考)リテラル:セット
//	
  セット専用のリテラルはないが、asによる型変換で表現できる	
  
def	
  s	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  as	
  Set	
  
assert	
  s.size()	
  ==	
  5	
  
assert	
  s.getClass()	
  ==	
  java.util.LinkedHashSet	
  
リテラル:マップ
//	
  専用リテラルの導入により、シンプルにマップを記述できる	
  
def	
  m	
  =	
  ['a':	
  1,	
  'b':	
  2,	
  'c':	
  3]	
  
assert	
  m.size()	
  ==	
  3	
  
assert	
  m.getClass()	
  ==	
  java.util.LinkedHashMap	
  
//	
  空マップ	
  
assert	
  [:].size()	
  ==	
  0	
  
//	
  キーに文字列を指定する場合はクォートを省略できる	
  
assert	
  m	
  ==	
  [a:	
  1,	
  b:	
  2,	
  c:	
  3]	
  
//	
  要素へのアクセス	
  
assert	
  m['a']	
  ==	
  1	
  	
  //	
  連想配列風	
  
assert	
  m.a	
  ==	
  1	
  	
  	
  	
  	
  //	
  プロパティアクセス風
アクセス修飾子
アクセス修飾子は基本的に飾りです
privateメンバにもアクセスできる
IDEなどで一応警告が出るぐらい
無印=public
パッケージプライベートは存在しない
一応、アノテーションで強引に宣言できる
@PackageScope	
  
基本は無印(public)でよい
その他、ドキュメンテーション目的として...
クラス内部だけで利用するものにprivateを付けたり
積極的に継承を想定しているものにprotectedを付けたり
メソッド呼び出し
//	
  引数の丸括弧が省略できる	
  
println("Hello")	
  
println	
  "Hello"	
  
//	
  引数がない場合は省略できない	
  
println()	
  
メソッド呼び出し
def	
  hello()	
  {	
  
	
  	
  	
  	
  "Hello!"	
  
}	
  
//	
  Stringでメソッド名を指定できる	
  
assert	
  "hello"()	
  ==	
  "Hello!"	
  
//	
  GStringを使ってもOK	
  
def	
  methodName	
  =	
  "hello"	
  
assert	
  "$methodName"()	
  ==	
  "Hello!"
メソッド呼び出し
//	
  名前付き引数?	
  
def	
  hello(Map	
  map)	
  {	
  
	
  	
  	
  	
  "Hello,	
  ${map.name}${map.period}"	
  
}	
  
assert	
  hello(period:	
  "!",	
  name:	
  "World")	
  ==	
  "Hello,	
  World!"	
  
//	
  これの[]を省略できるイメージ	
  
assert	
  hello([period:	
  "!",	
  name:	
  "World"])	
  ==	
  "Hello,	
  World!"
メソッド呼び出し
//	
  引数のデフォルト値	
  
def	
  bye(name	
  =	
  "World")	
  {	
  
	
  	
  	
  	
  "Good-­‐bye,	
  ${name}."	
  
}	
  
assert	
  bye()	
  ==	
  "Good-­‐bye,	
  World."	
  
assert	
  bye("Yesterday")	
  ==	
  "Good-­‐bye,	
  Yesterday."
コンストラクタ呼び出し
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  a	
  
	
  	
  	
  	
  String	
  b	
  
	
  	
  	
  	
  int	
  c	
  
}	
  
//	
  引数を受け取るコンストラクタを自前で書いていなければ、	
  
//	
  パラメータ付き引数を指定できる便利なコンストラクタが自動生成される	
  
def	
  sample	
  =	
  new	
  Sample(a:	
  "A",	
  c:	
  3,	
  b:	
  "B")	
  
println	
  sample.dump()	
  //	
  デバッグ時に便利なGDK:	
  Object#dump()	
  
	
  	
  	
  	
  //	
  =>	
  <Sample@3909c9e9	
  a=A	
  b=B	
  c=3>
Groovyの各種機能
クロージャ
他言語の第1級関数オブジェクトやクロージャと同等
JavaScript, Ruby, Perl, Lisp, ....
第一級オブジェクトとして、変数に代入したり引数
に渡したりできる
高階関数
無名内部クラスやJava 8のラムダ記法よりも次の点
で強力
クロージャを宣言した文法上のスコープ(レキシカルス
コープ)にある変数(ローカル変数を含む)を参照・変
更できる
クロージャ:定義と実行
//	
  クロージャを定義する	
  
Closure	
  c	
  =	
  {	
  
	
  	
  	
  	
  return	
  "Hello,	
  Closure!"	
  
}	
  
//	
  実行する	
  
assert	
  c.call()	
  ==	
  "Hello,	
  Closure!"	
  
//	
  callを省略することもできる	
  
assert	
  c()	
  ==	
  "Hello,	
  Closure!"
クロージャ:クロージャでの引数の受け取り
//	
  引数なし	
  
def	
  c0	
  =	
  {-­‐>	
  
	
  	
  	
  	
  "Hello,	
  Closure!"	
  
}	
  
assert	
  c0.call()	
  ==	
  "Hello,	
  Closure!"	
  
//	
  引数1つ	
  
def	
  c1	
  =	
  {	
  String	
  name	
  -­‐>	
  
	
  	
  	
  	
  "Hello,	
  ${name}!"	
  
}	
  
assert	
  c1.call("Closure")	
  ==	
  "Hello,	
  Closure!"	
  
//	
  引数2つ(片方を型省略してみる)	
  
def	
  c2	
  =	
  {	
  greeting,	
  String	
  name	
  -­‐>	
  
	
  	
  	
  	
  println	
  "${greeting},	
  ${name}!"	
  
}	
  
assert	
  c2.call("Hello",	
  "Closure")	
  ==	
  "Hello,	
  Closure!"	
  
//	
  引数宣言部「xx..	
  -­‐>」を省略した場合、暗黙引数の「it」が使える	
  
def	
  c	
  =	
  {	
  "Hello,	
  ${it}!"	
  }	
  
assert	
  c.call("Closure")	
  ==	
  "Hello,	
  Closure!"	
  
assert	
  c.call()	
  ==	
  "Hello,	
  null!"	
  //	
  引数を省略時はnull
クロージャ:クロージャを引数として渡す
//	
  渡されたクロージャを指定されたnameで実行するだけのメソッド	
  
def	
  justDoIt(String	
  name,	
  Closure	
  closure)	
  {	
  
	
  	
  	
  	
  closure.call(name)	
  
}	
  
//	
  普通に丸括弧の中にクロージャを書いた場合	
  
justDoIt("Taro",	
  {	
  name	
  -­‐>	
  println	
  "Hello,	
  ${name}!"	
  })	
  //=>	
  Hello,	
  Taro!	
  
//	
  最後の引数がクロージャの場合はこのように丸括弧の外に出して書ける	
  
justDoIt("Taro")	
  {	
  name	
  -­‐>	
  println	
  "Hello,	
  ${name}!"	
  }	
  	
  //=>	
  Hello,	
  Taro!	
  
//	
  このように、専用の文法があるかのように独自APIを定義できる	
  
justDoIt("Taro")	
  {	
  name	
  -­‐>	
  
	
  	
  	
  	
  println	
  "Hello,	
  ${name}!"	
  
}
最後の引数がClosure型であるところがポイント
(参考)クロージャ:高階関数とレキシカルスコープの例
def	
  createIdGenerator(prefix)	
  {	
  	
  //	
  この実引数と	
  
	
  	
  	
  	
  int	
  counter	
  =	
  1	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  このローカル変数が(finalではない!)	
  
	
  	
  	
  	
  Closure	
  c	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "${prefix}-­‐${counter++}"	
  //	
  クロージャごとに個別に保持される	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  return	
  c	
  //	
  クロージャを返す	
  
}	
  
def	
  genA	
  =	
  createIdGenerator("A")	
  
assert	
  genA()	
  ==	
  "A-­‐1"	
  
assert	
  genA()	
  ==	
  "A-­‐2"	
  
assert	
  genA()	
  ==	
  "A-­‐3"	
  
def	
  genB	
  =	
  createIdGenerator("B")	
  
assert	
  genB()	
  ==	
  "B-­‐1"	
  
assert	
  genB()	
  ==	
  "B-­‐2"	
  
assert	
  genB()	
  ==	
  "B-­‐3"	
  
assert	
  genA()	
  ==	
  "A-­‐4"
元々createIdGeneraterメソッド
のローカル変数であるcounter
が、クロージャごとに個別に管
理されているのがわかる
assertキーワード/Power Assert
Spockから正式採用したPower Assertが使える
Spockの方が更に先に進んでいて若干高機能(適合率を表示するとか)
Assertion	
  failed:	
  	
  
assert	
  a.collect	
  {	
  it	
  *	
  2	
  }.reverse()	
  ==	
  [6,	
  4,	
  0]	
  
	
  	
  	
  	
  	
  	
  	
  |	
  |	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  	
  	
  	
  	
  	
  	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  |	
  [2,	
  4,	
  6]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  [6,	
  4,	
  2]	
  false	
  
	
  	
  	
  	
  	
  	
  	
  [1,	
  2,	
  3]	
  
	
   at	
  ConsoleScript78.run(ConsoleScript78:2)
//	
  わざと3つ目を間違えてみる	
  
def	
  a	
  =	
  [1,	
  2,	
  3]	
  
assert	
  a.collect	
  {	
  it	
  *	
  2	
  }.reverse()	
  ==	
  [6,	
  4,	
  0]
Groovy JDK/GDK
GroovyがJavaの標準APIに追加した便利なAPI群
Javaの不便な点をAPIレベルで改善できる
printlnもObjectに実装されたGDK APIのひとつ
System.out.printlnに委譲しているだけ
後述するコレクションAPIもGDKとして実装されている
すべての品 えは以下のAPIドキュメントを参照のこと
http://docs.groovy-lang.org/docs/latest/html/groovy-jdk/
GDKの例
//	
  Groovy本家サイトのHTMLを表示する	
  
println	
  new	
  URL("http://groovy-­‐lang.org/").getText()	
  
//	
  ファイルの中身を表示する	
  
println	
  new	
  File("/my/some.text/").getText()
コレクション操作
各種の内部イテレーション記法が使える
外部イテレーション
forやiteratorなどで外側から要素を回す
内部イテレーション
各要素に適用すべき処理をクロージャ/ラムダなどでコレク
ションに渡して、コレクション自体が内部でループする
GroovyのコレクションAPIは、GDKとして提供されている
Java 8のStream APIもこちら
コレクション操作:リスト
List	
  l	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
//	
  各要素に対してクロージャの処理を適用する	
  
l.each	
  {	
  number	
  -­‐>	
  print	
  number	
  }	
  //=>	
  12345	
  
//	
  各要素に対してクロージャの処理を適用した結果のリストを取得する	
  
assert	
  l.collect	
  {	
  it	
  *	
  2	
  }	
  ==	
  [2,	
  4,	
  6,	
  8,	
  10]	
  
//	
  各要素に対してクロージャの処理を適用した結果が真の要素のみを残す	
  
assert	
  l.findAll	
  {	
  it	
  %	
  2	
  ==	
  0	
  }	
  ==	
  [2,	
  4]	
  
//	
  指定したセパレータで結合した文字列を返す	
  
assert	
  l.join(":")	
  ==	
  "1:2:3:4:5"	
  
//	
  合計値を算出する	
  
assert	
  l.sum()	
  ==	
  15
コレクション操作:マップ
Map	
  m	
  =	
  [a:	
  1,	
  b:	
  2,	
  c:	
  3]	
  
//	
  クロージャ引数を1つだけ宣言すると、Map.Entryが受け取れる	
  
m.each	
  {	
  Map.Entry	
  entry	
  -­‐>	
  
	
  	
  	
  	
  print	
  entry.key	
  +	
  entry.value	
  
}	
  //=>	
  a1b2c3	
  
//	
  クロージャ引数を2つ宣言すると、それぞれキーと値が受け取れる	
  
m.each	
  {	
  key,	
  value	
  -­‐>	
  
	
  	
  	
  	
  print	
  key	
  +	
  value	
  
}	
  //=>	
  a1b2c3	
  
//	
  各要素に対してクロージャの処理を適用した結果のリストを取得する	
  
assert	
  m.collect	
  {	
  "${it.key}:${it.value}"	
  }	
  ==	
  ["a:1",	
  "b:2",	
  "c:3"]	
  
//	
  クロージャの返す値が最も大きい要素を取得する	
  
assert	
  m.max	
  {	
  it.value	
  }.key	
  ==	
  "c"
マップにも基本的に同じAPIが用意されている
(コレクションの特性上、微妙に品 えは違う)
デフォルトimport済みパッケージ
高頻度で使うこれらのパッケージはデフォルトでimport済み
java.lang.*	
  
java.io.*	
  
java.net.*	
  
java.util.*	
  
groovy.lang.*	
  
groovy.util.*	
  
java.math.BigDecimal	
  
java.math.BigInteger	
  
(参考)別名をつけてimportすることもできる
import	
  java.lang.NullPointerException	
  as	
  NPE	
  
throw	
  new	
  NPE("aliased	
  import	
  sample")
GroovyBeans
JavaBeansに対するGroovyの強化サポート
プロパティに対するgetter/setterの自動生成
class	
  Book	
  {	
  
	
  	
  	
  	
  String	
  title	
  
}	
  
def	
  book	
  =	
  new	
  Book(title:	
  "プログラミングGROOVY")	
  
//	
  getterが自動生成されている	
  
assert	
  book.getTitle()	
  ==	
  "プログラミングGROOVY"	
  
//	
  setterが自動生成されている	
  
book.setTitle("JavaからGroovyへ")	
  
assert	
  book.getTitle()	
  ==	
  "JavaからGroovyへ"
GroovyBeans
class	
  GroovyBeansSample	
  {	
  
	
  	
  	
  	
  public	
  String	
  p	
  =	
  "PUBLIC"	
  
	
  	
  	
  	
  final	
  String	
  f	
  =	
  "FINAL"	
  
	
  	
  	
  	
  String	
  g	
  =	
  "GetterImplemented"	
  
	
  	
  	
  	
  String	
  getG()	
  {	
  "getGの戻り値:	
  $g"	
  }	
  
}	
  
def	
  sample	
  =	
  new	
  GroovyBeansSample()	
  
//	
  publicなどをアクセス修飾子を付けるとgetter/setterは自動生成されない	
  
sample.getP()	
  	
  	
  	
  	
  //=>	
  groovy.lang.MissingMethodException	
  
sample.setP("x")	
  	
  //=>	
  groovy.lang.MissingMethodException	
  
//	
  finalを付けるとsetterは自動生成されない	
  
assert	
  sample.getF()	
  ==	
  "FINAL"	
  
sample.setF("x")	
  	
  //=>	
  groovy.lang.MissingMethodException	
  
//	
  自前で実装したアクセサメソッドは自動生成されない	
  
assert	
  sample.getG()	
  ==	
  "getGの戻り値:	
  GetterImplemented"	
  
sample.setG("xxx")	
  
assert	
  sample.getG()	
  ==	
  "getGの戻り値:	
  xxx"
常に無条件で自動生成するわけではない
GroovyBeans
プロパティアクセスの簡略記法
class	
  Book	
  {	
  
	
  	
  	
  	
  String	
  title	
  
}	
  
def	
  book	
  =	
  new	
  Book(title:	
  "プログラミングGROOVY")	
  
//	
  インスタンス変数への直接参照のようにみえるがgetterを経由している	
  
assert	
  book.title	
  ==	
  "プログラミングGROOVY"	
  
//	
  インスタンス変数への直接代入のようにみえるがsetterを経由している	
  
book.title	
  =	
  "JavaからGroovyへ"	
  
assert	
  book.title	
  ==	
  "JavaからGroovyへ"	
  
//	
  getXxx()という名前の引数なしのメソッドであればプロパティ記法でアクセスできる	
  
//	
  つまり、GroovyBeansに限らず名前規約が一致していれば、この簡略記法は使える	
  
assert	
  book.class	
  ==	
  book.getClass()
Grape
Mavenリポジトリから直接Jarをダウンロードし、
クラスパスに通してからスクリプトを実行できる
ダウンロードしたファイルは $HOME/.groovy/grapes
配下に格納される
@Grab('org.apache.commons:commons-­‐lang3:3.2')	
  
import	
  org.apache.commons.lang3.StringUtils	
  
List	
  l	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
assert	
  StringUtils.join(l,	
  ':')	
  ==	
  "1:2:3:4:5"	
  
//	
  本当はこの程度の処理であればGDKで十分	
  
assert	
  l.join(':')	
  ==	
  "1:2:3:4:5"
後半で示すサンプルはGrapeを使って即
実行できるスクリプト形式にしている
便利な演算子
等値演算子 ==
Javaではインスタンスの同一性のための使うが、Groovyではequals呼び出
しになっている
Stringの比較で普通に==が使える!
インスタンス同一性のチェックにはObject#is()を使う
エルビス演算子 ?:
A	
  ?:	
  B	
  
三項演算子 A	
  ?	
  A	
  :	
  B	
  の省略形
セーフナビゲーション演算子 ?.
a?.b?.c()	
  
nullではない場合のみ、右側の呼び出しを続行する
展開ドット演算子 *.
[a:1,	
  b:2,	
  c:3]*.value	
  ==	
  [1,	
  2,	
  3]	
  
collect	
  {	
  it.value	
  }	
  の短縮形のイメージ
#ccc_cd1 で紹介されました!
#ccc_cd1 で紹介されました!
レンジ(範囲)
範囲を表すコレクション
groovy.lang.Range
始点と終点を指定してその間の要素をIterableに扱う
for	
  (int	
  i	
  :	
  1..9)	
  {	
  //	
  閉区間(9を含む)	
  
	
  	
  	
  	
  print	
  i	
  
}	
  
//=>	
  123456789	
  
for	
  (int	
  i	
  :	
  1..<9)	
  {	
  //	
  半開区間(9を含まない)	
  
	
  	
  	
  	
  print	
  i	
  
}	
  
//=>	
  12345678	
  
//	
  Range#toList()でリストに変換できる	
  
assert	
  (1..5).toList()	
  ==	
  [1,	
  2,	
  3,	
  4,	
  5]
正規表現サポート
正規表現をサポートする演算子やリテラルがある
//	
  「==~」完全一致によるマッチング結果の真偽値を返す	
  
assert	
  	
  	
  	
  "abc"	
  ==~	
  /a.c/	
  
assert	
  !	
  ("abc"	
  ==~	
  /bc/)	
  	
  //	
  部分一致ではない	
  
//	
  実際は、Matcher#matches()の呼び出しになっている	
  
assert	
  	
  	
  "abc".matches(/a.c/)	
  
assert	
  !	
  "abc".matches(/bc/)	
  
//	
  「=~」部分一致によるマッチング結果のMatcherオブジェクトを返す	
  
assert	
  "abc"	
  =~	
  /a.c/	
  
assert	
  "abc"	
  =~	
  /bc/	
  	
  	
  	
  	
  	
  	
  //	
  部分一致OK	
  
//	
  実は、演算自体の戻り値はMatcherオブジェクトになっている	
  
//	
  Matcherが真偽値判定されるタイミングで、	
  
//	
  Matcher#find()が裏で呼ばれてその結果が返っている	
  
assert	
  ("abc"	
  =~	
  /a.c/).getClass()	
  ==	
  java.util.regex.Matcher
論理値/Groovy Truth
Groovyではboolean/Boolean以外の値についても、
真偽判定できる
assert	
  !	
  0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  整数:	
  0は偽	
  
assert	
  	
  	
  1	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  整数:	
  0以外は真	
  
assert	
  !	
  []	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  リスト:	
  空リストは偽	
  
assert	
  	
  	
  ["a"]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  リスト:	
  空リスト以外は真	
  
assert	
  !	
  [:]	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  マップ:	
  空マップは偽	
  
assert	
  	
  	
  [key:'value']	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  マップ:	
  空マップ以外は真	
  
assert	
  !	
  ""	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  文字列:	
  空文字列は偽	
  
assert	
  	
  	
  "a"	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  文字列:	
  空文字列以外は真	
  
assert	
  !("abcdefg"	
  =~	
  /a.*X/)	
  	
  	
  //	
  正規表現:	
  マッチしないと偽	
  
assert	
  	
  	
  "abcdefg"	
  =~	
  /cde/	
  	
  	
  	
  	
  //	
  正規表現:	
  マッチすると真	
  
assert	
  !	
  null	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  nullは偽	
  
assert	
  	
  	
  new	
  Object()	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  それ以外のオブジェクト:	
  null以外は真
演算子オーバーロード
GroovyではJavaと同等の各種演算子が使える
実は、それぞれの演算子は対応する特定のメソッド呼び出しに変換されている
つまり、演算子オーバロードが可能
GDKでも多数活用されている
例えば、「+」→「plus()」、「-」→「minus()」、「<<」→「leftShift()」
演算子と対応するメソッドの一覧
http://groovy-lang.org/operators.html#Operator-Overloading
class	
  MyObject	
  {	
  
	
  	
  	
  	
  String	
  name	
  
	
  	
  	
  	
  MyObject(name)	
  {	
  this.name	
  =	
  name	
  }	
  
	
  	
  	
  	
  MyObject	
  plus(MyObject	
  o)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  MyObject(name	
  +	
  ":"	
  +	
  o.name)	
  
	
  	
  	
  	
  }	
  
}	
  
def	
  obj1	
  =	
  new	
  MyObject("OBJECT_1")	
  
def	
  obj2	
  =	
  new	
  MyObject("OBJECT_2")	
  
def	
  obj3	
  =	
  obj1	
  +	
  obj2	
  
assert	
  obj3.name	
  ==	
  "OBJECT_1:OBJECT_2"
AST変換
抽象構文木(Abstract Syntax Tree)レベルでのコード変換技術
コンパイルの過程で、アノテーションでマーキングした対象箇所に、
任意のコードの追加・置換ができる
Groovyシンタックスの意味自体を改変する「グローバルAST変換」
技術もあるがあまり使われない
例
Grape(@Grab)
ロギング(@Log, @Commons, @Log4j, @Slf4j)
シングルトン(@Singleton)
不変オブジェクト(@Immutable)
自前クラスの基本要素(@ToString, @EqualsAndHashCode,
@Canonical, @InheritConstructors)
AST変換: @Grabと@Log
//	
  Mavenセントラルリポジトリからダウンロード&クラスパスに指定	
  
@Grab("log4j:log4j")	
  
import	
  groovy.util.logging.Log4j	
  
@Log4j	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  def	
  doIt()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ロガーとしてlog変数が使える	
  
	
  	
  	
  	
  	
  	
  	
  	
  log.fatal	
  "Hello"	
  
	
  	
  	
  	
  }	
  
}	
  
new	
  Sample().doIt()	
  
//=>	
  FATAL	
  -­‐	
  Hello
AST変換: @Singleton
@groovy.lang.Singleton	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  value	
  
}	
  
//	
  インスタンス初期化機構とgetInstance()クラスメソッドが	
  
//	
  追加されるので、シングルトンとしてすぐに使える	
  
assert	
  Sample.getInstance().value	
  ==	
  null	
  
Sample.instance.value	
  =	
  "シングルトン"	
  
assert	
  Sample.instance.value	
  ==	
  "シングルトン"	
  
//	
  もちろん同一インスタンス	
  
assert	
  sample.instance.is(Sample.instance)
AST変換: @Immutable
@groovy.transform.Immutable	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  value	
  
}	
  
def	
  sample	
  =	
  new	
  Sample(value:	
  "HOGE")	
  
sample.value	
  =	
  "変更できない"	
  
//=>	
  groovy.lang.ReadOnlyPropertyException:	
  
//	
  	
  	
  	
  	
  Cannot	
  set	
  readonly	
  property:	
  value	
  for	
  class:	
  Sample	
  
AST変換: @ToString, @EqualsAndHashCode, @TupleConstructors
@groovy.transform.TupleConstructor	
  
@groovy.transform.ToString	
  
@groovy.transform.EqualsAndHashCode	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  a	
  
	
  	
  	
  	
  String	
  b	
  
	
  	
  	
  	
  int	
  c	
  
}	
  
//	
  @TupleConstructorによって宣言したフィールドの順に引数を受け取るコンストラクタが生成される	
  
def	
  sample	
  =	
  new	
  Sample("A",	
  "B",	
  3)	
  
//	
  @ToStringによってそれっぽい文字列を構成するtoString()が生成される	
  
println	
  sample.toString()	
  //	
  =>	
  Sample(A,	
  B,	
  3)	
  
//	
  @EqualsAndHashCodeによって、プロパティの値をベースにした等値判定をするequals()が生成される	
  
assert	
  sample	
  ==	
  new	
  Sample("A",	
  "B",	
  3)	
  
assert	
  sample	
  !=	
  new	
  Sample("A",	
  "B",	
  123)	
  
//	
  もちろん、equals()の実装契約として必須であるhashCode()も合わせて実装されている	
  
assert	
  sample.hashCode()	
  ==	
  new	
  Sample("A",	
  "B",	
  3).hashCode()	
  
assert	
  sample.hashCode()	
  !=	
  new	
  Sample("A",	
  "B",	
  123).hashCode()	
  
//	
  (参考)	
  @Canonicalは、@ToStringと@EqualsAndHashCodeの組み合わせのエイリアス
静的Groovy
@TypeChecked
コンパイル時に静的型チェックする
lintのようなもの
実行時はいつも通り動的に
@CompileStatic
指定した範囲を静的型付けとしてコンパイルする
実行時も静的に(性能的に有利)
Groovyの動的な側面に依存した機能が使えない
ダックタイピング、privateの呼び出し、など
性能的にカリカリにしたい箇所に、部分的に付けると良い
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  
	
  	
  	
  	
  
	
  	
  	
  	
  def	
  store(name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  list	
  <<	
  name	
  
	
  	
  	
  	
  }	
  
}	
  
def	
  list	
  =	
  new	
  MyList()	
  
list.store	
  "A"	
  
list.store	
  "B"	
  
list.store	
  "C"	
  
println	
  list.dump()	
  
//=>	
  <MyList@5c042a81	
  list=[A,	
  B,	
  C]>
StringインスタンスをObject型で
受けとって、listに追加する
期待通り動く
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  @groovy.transform.TypeChecked	
  
	
  	
  	
  	
  def	
  store(name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  list	
  <<	
  name	
  
	
  	
  	
  	
  }	
  
}	
  
def	
  list	
  =	
  new	
  MyList()	
  
list.store	
  "A"	
  
list.store	
  "B"	
  
list.store	
  "C"	
  
println	
  list.dump()	
  
//=>	
  [Static	
  type	
  checking]	
  -­‐	
  Cannot	
  call	
  <T>	
  java.util.List	
  
<String>#leftShift(T)	
  with	
  arguments	
  [java.lang.Object]	
  	
  
	
  at	
  line:	
  7,	
  column:	
  9
コンパイル時にエラーが発生する
このメソッドを
静的型チェックすると...
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  @groovy.transform.TypeChecked	
  
	
  	
  	
  	
  def	
  store(String	
  name)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  list	
  <<	
  name	
  
	
  	
  	
  	
  }	
  
}	
  
def	
  list	
  =	
  new	
  MyList()	
  
list.store	
  "A"	
  
list.store	
  "B"	
  
list.store	
  "C"	
  
println	
  list.dump()	
  
//=>	
  <MyList@5c042a81	
  list=[A,	
  B,	
  C]>
String型を明示すると...
また動くようになった!
静的Groovy: 非@CompileStatic
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  <	
  2)	
  return	
  1	
  
	
  	
  	
  	
  return	
  fib(n	
  -­‐	
  2)	
  +	
  fib(n	
  -­‐	
  1)	
  
}	
  
def	
  start	
  =	
  System.currentTimeMillis()	
  
def	
  num	
  =	
  40	
  
def	
  ans	
  =	
  fib(num)	
  
println	
  "fib($num)	
  =	
  ${ans}"	
  
println	
  "Total:	
  ${System.currentTimeMillis()	
  -­‐	
  start}	
  msec"	
  
//=>	
  fib(40)	
  =	
  165580141	
  
//	
  	
  	
  Total:	
  1575	
  msec
静的Groovy: @CompileStatic
import	
  groovy.transform.CompileStatic	
  
@CompileStatic	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  <	
  2)	
  return	
  1	
  
	
  	
  	
  	
  return	
  fib(n	
  -­‐	
  2)	
  +	
  fib(n	
  -­‐	
  1)	
  
}	
  
def	
  start	
  =	
  System.currentTimeMillis()	
  
def	
  num	
  =	
  40	
  
def	
  ans	
  =	
  fib(num)	
  
println	
  "fib($num)	
  =	
  ${ans}"	
  
println	
  "Total:	
  ${System.currentTimeMillis()	
  -­‐	
  start}	
  msec"	
  
//=>	
  fib(40)	
  =	
  165580141	
  
//	
  	
  	
  Total:	
  569	
  msec 約3倍!<1575 msec
(参考)AST変換: @Memoized
import	
  groovy.transform.Memoized	
  
@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  <	
  2)	
  return	
  1	
  
	
  	
  	
  	
  return	
  fib(n	
  -­‐	
  2)	
  +	
  fib(n	
  -­‐	
  1)	
  
}	
  
def	
  start	
  =	
  System.currentTimeMillis()	
  
def	
  num	
  =	
  40	
  
def	
  ans	
  =	
  fib(num)	
  
println	
  "fib($num)	
  =	
  ${ans}"	
  
println	
  "Total:	
  ${System.currentTimeMillis()	
  -­‐	
  start}	
  msec"	
  
//=>	
  fib(40)	
  =	
  165580141	
  
//	
  	
  	
  Total:	
  4	
  msec !!!!!!?????? <569 msec <1575 msec
参照透過な関数の場合、
メモ化(引数と結果の組み合わせ
をキャッシュ)の効果が強力に活
用できる場合がある
Groovy
コードの実行
実行可能なコード形式
実行可能なコード形式
Groovyプログラムとして実行可能なのは...
mainメソッド持つクラス(Javaと同等)
Groovyスクリプト
JUnitのテストケース
Runnableの実装クラス
mainメソッド持つクラス
//	
  in	
  HelloMain.groovy	
  
class	
  HelloMain	
  {	
  
	
  	
  	
  	
  static	
  void	
  main(String...	
  args)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "Hello,	
  Main!"	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  Main!
Groovyスクリプト
//	
  in	
  hello.groovy	
  
println	
  "Hello,	
  Script!"	
  
//=>	
  Hello,	
  Script!
クラスの外側のルートレベルで直接コード
が書かれている=Groovyスクリプト
ちなみに、コンパイルされると、
Scriptクラスのインスタンスになる
public	
  class	
  hello	
  extends	
  groovy.lang.Script	
  {	
  
	
  	
  public	
  static	
  transient	
  boolean	
  __$stMC;	
  
	
  	
  public	
  hello();	
  
	
  	
  public	
  hello(groovy.lang.Binding);	
  
	
  	
  public	
  static	
  void	
  main(java.lang.String...);	
  
	
  	
  public	
  java.lang.Object	
  run();	
  
	
  	
  protected	
  groovy.lang.MetaClass	
  $getStaticMetaClass();	
  
}
JUnitのテストケース
//	
  in	
  HelloTest.groovy	
  
import	
  junit.framework.TestCase	
  
class	
  HelloTest	
  extends	
  TestCase	
  {	
  
	
  	
  	
  	
  void	
  testHello()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "Hello,	
  JUnit!"	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  .Hello,	
  JUnit!	
  
//	
  
//	
  	
  	
  Time:	
  0.047	
  
//	
  
//	
  	
  	
  OK	
  (1	
  test)	
  
//
GroovyがJUnitを同梱しているので
別途JARを用意する必要はない
Runnableの実装クラス
//	
  in	
  HelloRunnable.groovy	
  
class	
  HelloRunnable	
  implements	
  Runnable	
  {	
  
	
  	
  	
  	
  void	
  run()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "Hello,	
  Runnable!"	
  
	
  	
  	
  	
  }	
  
}	
  
//=>	
  Hello,	
  Runnable!
実行可能なコード形式
Groovyプログラムとして実行可能なのは...
mainメソッド持つクラス(Javaと同等)
Groovyスクリプト
JUnitのテストケース
Runnableの実装クラス
今回のケースでは
とりあえず、これで十分
実行方法
各種実行方法
groovy
java -jar groovy-all.jar
groovyc + java
groovyConsole
groovysh
GroovyServ
スクリプト起動の高速化
Groovy Web Console
https://groovyconsole.appspot.com/
各種実行方法
groovy
java -jar groovy-all.jar
groovyc + java
groovyConsole
groovysh
GroovyServ
スクリプト起動の高速化
Groovy Web Console
https://groovyconsole.appspot.com/
だいたいこの辺を使っておけばOK
groovyコマンド
java -jar groovy-all.jar == groovyコマンド
All-In-OneのJARファイルさえあれば、
groovyコマンドがなくても実行できる!
groovyc + java
滅多に使わない
groovyConsole
編集して、
Ctrl+Rで実行できる
実行結果を表示
Ctrl+Wでクリア
引数なしでもOK
groovysh
限定的ながらも
Tabでコード補完ができる
高速起動 GroovyServ
http://kobo.github.io/groovyserv/
Groovy web console
クリックで実行
https://groovyconsole.appspot.com/
インストール不要で手軽に試せる
ユースケース
(再掲)Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
開発支援ツールとしての活用
Groovyは、たとえ対象システムの開発言語として採
用しない場合でも、Javaによる開発を支援するツー
ルとして非常に有用
な
るほ
ど
ね
Java APIのお試し
例えば
標準APIを試す
○○の場合はどういう動作をするんだったっけ?
正規表現はこれで良いのかな?
初めて使うサードパーティ製のライブラリを試す
お試し環境
groovyConsole上で試す
シンプルなエディタで試行錯誤できる
Grapeを使ってサードパーティライブラリも試せる
わかりやすくてお手軽
groovyshで試す
JavaとGroovyの標準APIであれば、Tabによるコード補完
が効く点でちょっと便利
エディタ+groovy (or GroovyServ)
エディタの機能ですぐに実行できる環境をつくると便利
(例)vim + quickrun.vim + GroovyServ
http://nobeans.hatenablog.com/entry/20111024/1319435155
ちなみに、この資料のサンプルコードは
ほとんどgroovyConsoleで書きました
groovyConsoleの例
XMLのパース
例えば
設定ファイル内容の一覧を出力する
JUnitのテストレポートをパースして自動的に進 報
告資料に追加する
Rest APIの結果をチェックする
XmlParser/XmlSlurper
Groovy標準APIのXmlParserが便利
兄弟分として XmlSlurper(∼すらーぱー)がある
XmlParser:DOM的(インメモリ、変更可能)
XmlSlurper:SAX的(ストリーム処理、参照専用)
細かい点で差異はあるものの、シンプルな参照に限定し
たAPIの使い勝手はほぼ同じ
メモリ展開が難しい巨大なファイルを対象とするのでな
ければ、XmlParserを選択しておけばOK
XMLParserで属性やテキストを参照する例
def	
  inputXml	
  =	
  """	
  
<root>	
  
	
  	
  <items>	
  
	
  	
  	
  	
  <item	
  id="1"	
  name="あいうえお">OK</item>	
  
	
  	
  	
  	
  <item	
  id="2"	
  name="かきくけこ">NG</item>	
  
	
  	
  	
  	
  <item	
  id="3"	
  name="さしすせそ">OK</item>	
  
	
  	
  </items>	
  
</root>	
  
"""	
  
def	
  root	
  =	
  new	
  XmlParser().parseText(inputXml)	
  //	
  <root>に対応するgroovy.util.Nodeオブジェクト	
  
//	
  すべてのitem要素をフォーマットして出力する	
  
root.items.item.each	
  {	
  Node	
  item	
  -­‐>	
  
	
  	
  	
  	
  println	
  "${item.@id}:	
  ${item.@name}	
  =>	
  ${item.text()}"	
  
}	
  
//=>	
  1:	
  あいうえお	
  =>	
  OK	
  
//	
  	
  	
  2:	
  かきくけこ	
  =>	
  NG	
  
//	
  	
  	
  3:	
  さしすせそ	
  =>	
  OK	
  
//	
  OKのitem要素のみをフォーマットして出力する	
  
root.items.item.findAll	
  {	
  it.text()	
  ==	
  "OK"	
  }.each	
  {	
  
	
  	
  	
  	
  println	
  "${it.@id}:	
  ${it.@name}	
  =>	
  ${it.text()}"	
  
}	
  
//=>	
  1:	
  あいうえお	
  =>	
  OK	
  
//	
  	
  	
  3:	
  さしすせそ	
  =>	
  OK
この時点でXMLはパースされて、
Nodeツリーがメモリ上に展開済み
GPathという記法でNodeのコレクションを特定
属性値は「@+属性名」、
子要素のテキストは「text()」で参照
each, findAllなどのコレクション操作が
そのまま適用できる
HTML/XMLの出力
例えば
自動的に収集した情報を元にHTMLレポートを出力
する
システムにインポートするXMLファイルを生成する
MarkupBuilder
Groovy標準APIのMarkupBuilderが便利
タグでマークアップされたテキストを生成する
波括弧のブロックで階層構造を表現できる
if文やループ制御構文が使える
マップの情報を元にHTMLを出力する例
def	
  generateHtml	
  =	
  {	
  data,	
  writer	
  -­‐>	
  
	
  	
  def	
  reportTitle	
  =	
  '試験実施日時報告'	
  
	
  	
  def	
  formatCount	
  =	
  {	
  now,	
  latest	
  -­‐>	
  
	
  	
  	
  	
  def	
  diffCount	
  =	
  now	
  -­‐	
  latest	
  
	
  	
  	
  	
  return	
  "${now}	
  (${diffCount	
  >	
  0	
  ?	
  "+"	
  :	
  ""}${diffCount})"	
  
	
  	
  }	
  
	
  	
  new	
  groovy.xml.MarkupBuilder(writer).html	
  {	
  
	
  	
  	
  	
  head	
  {	
  
	
  	
  	
  	
  	
  	
  title	
  reportTitle	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  body(style:	
  "background:	
  #afa")	
  {	
  
	
  	
  	
  	
  	
  	
  h1	
  reportTitle	
  
	
  	
  	
  	
  	
  	
  h2	
  '試験件数等'	
  
	
  	
  	
  	
  	
  	
  ul	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "試験項目数:	
  ${formatCount(data.tests,	
  data.latest.tests)}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "終了件数:	
  ${formatCount(data.done,	
  data.latest.done)}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "バグ件数:	
  ${formatCount(data.issues,	
  data.latest.issues)}"	
  
	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  h2	
  '備考'	
  
	
  	
  	
  	
  	
  	
  if	
  (data.remarks)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ul	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  data.remarks.each	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  li(it)	
  
	
  	
  }	
  }	
  }	
  }	
  }	
  
}	
  
def	
  data	
  =	
  [	
  
	
  	
  tests:	
  1230,	
  done:	
  	
  	
  350,	
  issues:	
  123,	
  
	
  	
  latest:	
  [tests:	
  1235,	
  done:	
  	
  	
  320,	
  issues:	
  93],	
  
	
  	
  remarks:	
  ["進 は特に問題なし",	
  "インフルエンザが流行中なので不安"]	
  
]	
  
new	
  File("/tmp/daily-­‐test-­‐report.html").withWriter	
  {	
  writer	
  -­‐>	
  
	
  	
  generateHtml(data,	
  writer)	
  
}
マップの情報を元にHTMLを出力する例
	
  	
  //...	
  
	
  	
  new	
  groovy.xml.MarkupBuilder(writer).html	
  {	
  
	
  	
  	
  	
  head	
  {	
  
	
  	
  	
  	
  	
  	
  title	
  reportTitle	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  body(style:	
  "background:	
  #afa")	
  {	
  
	
  	
  	
  	
  	
  	
  h1	
  reportTitle	
  
	
  	
  	
  	
  	
  	
  h2	
  '試験件数等'	
  
	
  	
  	
  	
  	
  	
  ul	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "試験項目数:	
  ${formatCount(data.tests,	
  data.latest.tests)}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "終了件数:	
  ${formatCount(data.done,	
  data.latest.done)}"	
  
	
  	
  	
  	
  	
  	
  	
  	
  li	
  "バグ件数:	
  ${formatCount(data.issues,	
  data.latest.issues)}"	
  
	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  h2	
  '備考'	
  
	
  	
  	
  	
  	
  	
  if	
  (data.remarks)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  ul	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  data.remarks.each	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  li(it)	
  
	
  	
  }	
  }	
  }	
  }	
  }	
  
	
  	
  //...
MarkupBuilderについてもう少し補足
def	
  builder	
  =	
  new	
  groovy.xml.MarkupBuilder()	
  
def	
  existMethod(a)	
  {	
  "EXIST_METHOD:	
  ${a}"	
  }	
  
//	
  最初の呼び出しで使った名前がルート要素のタグ名になる	
  
builder.aaa	
  {	
  
	
  	
  	
  	
  //	
  存在しないメソッド名で呼び出すと要素宣言と見なされる。引数は子要素になる。	
  
	
  	
  	
  	
  bbb	
  "BBB"	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  //	
  引数をマップで指定すると属性値になる	
  
	
  	
  	
  	
  ccc(c1:	
  "C1",	
  c2:	
  "C2")	
  
	
  	
  	
  	
  //	
  引数としてクロージャを渡すとネストになる	
  
	
  	
  	
  	
  ddd	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  xxx	
  "XXX"	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  制御構文がそのまま使える	
  
	
  	
  	
  	
  if	
  (false)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ここが実行されなければ出力されない	
  
	
  	
  	
  	
  	
  	
  	
  	
  ignoredThis	
  "IGNORED"	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  //	
  存在するメソッドであれば単にそのメソッドが呼ばれるだけで要素は生成されない	
  
	
  	
  	
  	
  //	
  存在しないメソッドを実行しようとすることが、要素生成のトリガとなる	
  
	
  	
  	
  	
  existMethod	
  "ただのメソッド呼び出し"	
  
}
<aaa>	
  
	
  	
  <bbb>BBB</bbb>	
  
	
  	
  <ccc	
  c1='C1'	
  c2='C2'	
  />	
  
	
  	
  <ddd>	
  
	
  	
  	
  	
  <xxx>XXX</xxx>	
  
	
  	
  </ddd>	
  
</aaa>	
  
このように、Groovyの「*Builder」は存在しな
いメソッド呼び出し(methodMissing)をトリガ
にして構造をビルドしていくクラスになっている
HTMLスクレイピング
例えば
定期レポートのための情報を収集する
開発中のWebアプリのテストの一環として、ある画
面のHTMLを取得して、内容をチェックする
HTMLスクレイピング
URL#getText()
HTMLテキストを取得すればいい場合は一番簡単
XmlParser/XmlSlurper
整形式であるXHMLの場合は単品でOK
非整形式のHTMLの場合はNekoHTMLを併用すればOK
http://nekohtml.sourceforge.net/
jsoup
jQuery風のセレクタAPIが使える
http://jsoup.org/
HTMLスクレイピング: URL#getText()
String	
  html	
  =	
  new	
  URL("http://groovy-­‐lang.org/").text	
  
//	
  1行ずつチェックしてURLをパースする	
  
def	
  urls	
  =	
  html	
  
	
  	
  	
  	
  //	
  1行ずつのリストにする	
  
	
  	
  	
  	
  .readLines()	
  
	
  	
  	
  	
  //	
  行中にURLパターンがあったらそれを返す(なければnull)	
  
	
  	
  	
  	
  .collect	
  {	
  line	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (line	
  =~	
  $/.*(https?://[a-­‐zA-­‐Z0-­‐9%?._]+).*/$)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  java.util.regex.Matcher.lastMatcher.group(1)	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  nullを除外する	
  
	
  	
  	
  	
  .findAll	
  {	
  it	
  !=	
  null	
  }	
  
	
  	
  	
  	
  //	
  重複したURLを除去する	
  
	
  	
  	
  	
  .unique()	
  
//	
  ソートして表示する	
  
urls.sort().each	
  {	
  println	
  it	
  }
HTMLスクレイピング: XmlParser + NekoHTML
@Grab('net.sourceforge.nekohtml:nekohtml:1.9.21')	
  
import	
  org.cyberneko.html.parsers.SAXParser	
  
import	
  groovy.util.Node	
  
def	
  parser	
  =	
  new	
  XmlParser(new	
  SAXParser())	
  
Node	
  html	
  =	
  parser.parse("http://groovy-­‐lang.org/")	
  
//	
  1行ずつチェックしてURLをパースする	
  
def	
  urls	
  =	
  html	
  
	
  	
  	
  	
  //	
  html配下のすべての子要素のaタグのhref属性値を集める	
  
	
  	
  	
  	
  .'**'.A.@href	
  
	
  	
  	
  	
  //	
  http(s)のものだけ抽出する	
  
	
  	
  	
  	
  .findAll	
  {	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  it	
  ==~	
  /https?:.*/	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  重複したURLを除去する	
  
	
  	
  	
  	
  .unique()	
  
//	
  ソートして表示する	
  
urls.sort().each	
  {	
  println	
  it	
  }
HTMLスクレイピング: jsoup
@Grab('org.jsoup:jsoup:1.8.1')	
  
import	
  org.jsoup.Jsoup	
  
import	
  org.jsoup.nodes.Document	
  
Document	
  doc	
  =	
  Jsoup.connect("http://groovy-­‐lang.org/").get()	
  
def	
  urls	
  =	
  doc	
  
	
  	
  	
  	
  //	
  すべてのaタグのhref属性を集める	
  
	
  	
  	
  	
  .select('a')*.attr("href")	
  
	
  	
  	
  	
  //	
  http(s)のものだけ抽出する	
  
	
  	
  	
  	
  .findAll	
  {	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  it	
  ==~	
  /https?:.*/	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  重複したURLを除去する	
  
	
  	
  	
  	
  .unique()	
  
//	
  ソートして表示する	
  
urls.sort().each	
  {	
  println	
  it	
  }
Groovy SQLによる
RDBMS操作
例えば
テスト用ダミーデータをDBに大量投入する
定期レポートのための情報を収集する
保守のためデータベースの内容を定期的に監視する
あるシステムから別のシステムにデータを移行する
Groovy SQL
Groovy標準APIのGroovy SQLが便利
クエリ発行と結果のResultSetからの値の取り出しなど
が簡単に実行できる
DataSetを使うと、コレクション操作のようにレコード
の追加やイテレーションが実行できる
Groovy SQLでH2を操作する
@Grab('com.h2database:h2')	
  
@GrabConfig(systemClassLoader=true)	
  //	
  JDBCはシステムクラスローダから探されるので必要	
  
import	
  groovy.sql.Sql	
  
//	
  別途DataSourceやConnectionを用意するなら、Sqlのコンストラクタに渡せばOK	
  
def	
  db	
  =	
  Sql.newInstance("jdbc:h2:mem:sample",	
  "org.h2.Driver")	
  
//	
  Sql#execute()でDDLを実行する	
  
db.execute	
  """	
  
create	
  table	
  person	
  (	
  
	
  	
  	
  	
  name	
  varchar(255),	
  
	
  	
  	
  	
  age	
  int	
  
)	
  
"""	
  
//	
  Sql#executeUpdate()使うと、変更した行数が返る	
  
insertSql	
  =	
  "insert	
  into	
  person	
  (name,	
  age)	
  values	
  (?,	
  ?)"	
  
assert	
  db.executeUpdate(insertSql,	
  ['Mike',	
  	
  13])	
  ==	
  1	
  
assert	
  db.executeUpdate(insertSql,	
  ['Junko',	
  14])	
  ==	
  1	
  
//	
  Sql#eachRow()は1行ごとに処理する(リソース低負荷)	
  
db.eachRow('select	
  *	
  from	
  person')	
  {	
  row	
  -­‐>	
  
	
  	
  	
  	
  println	
  row.name	
  
}	
  
//=>	
  Mike	
  
//	
  	
  	
  Junko	
  
//	
  Sql#rows()は結果をすべてメモリ上に取得する(リソース高負荷)	
  
println	
  db.rows('select	
  *	
  from	
  person').collect	
  {	
  it.name	
  }	
  
//=>	
  [Mike,	
  Junko]
DataSetを使う例
@Grab('com.h2database:h2')	
  
@GrabConfig(systemClassLoader=true)	
  //	
  JDBCはシステムクラスローダから探されるので必要	
  
import	
  groovy.sql.Sql	
  
//	
  別途DataSourceやConnectionを用意するなら、Sqlのコンストラクタに渡せばOK	
  
def	
  db	
  =	
  Sql.newInstance("jdbc:h2:mem:sample",	
  "org.h2.Driver")	
  
//	
  Sql#execute()でDDLを実行する	
  
db.execute("""	
  
create	
  table	
  person	
  (	
  
	
  	
  	
  	
  name	
  varchar(255),	
  
	
  	
  	
  	
  age	
  int	
  
)	
  
""")	
  
//	
  DataSetを使うとコレクションオブジェクト風にレコード操作ができる	
  
import	
  groovy.sql.DataSet	
  
DataSet	
  people	
  =	
  db.dataSet('person')	
  
people.add(name:	
  'Mike',	
  age:13)	
  
people.add(name:	
  'Junko',	
  age:	
  14)	
  
people.add(name:	
  'Ken',	
  age:	
  23)	
  
people.each	
  {	
  
	
  	
  	
  	
  println	
  "${it.name}	
  (${it.age})"	
  
}	
  
//=>	
  Mike	
  (13)	
  
//	
  	
  	
  Junko	
  (14)	
  
//	
  	
  	
  Ken	
  (23)
GExcelAPIによる
Excel操作
例えば
ダミーデータの定義表として読み込む
Excelデータから特定セルの値を読み込んで集計する
コード生成の入力データとして
GExcelAPI
https://github.com/nobeans/gexcelapi
Apache POIのGroovy風ラッパーライブラリ
POIを直接使った場合、セルを特定するイ
ンデックス指定がとても分かりづらい
GExcelAPIを使うと、Excelのセルラベルで
ある「A1」でアクセスできる!
GExcelAPI
@GrabResolver(name="bintray",	
  root="http://dl.bintray.com/nobeans/maven")	
  
@Grab("org.jggug.kobo:gexcelapi:0.4")	
  
import	
  org.jggug.kobo.gexcelapi.GExcel	
  
def	
  book	
  =	
  GExcel.open("/tmp/sample.xlsx")	
  
def	
  sheet	
  =	
  book[0]	
  	
  //	
  1シート目	
  
//	
  Excel風なDSLでセルの値を取得する	
  
println	
  sheet.A1.value	
  	
  //=>	
  A1の値	
  
println	
  sheet.B2.value	
  	
  //=>	
  B2の値	
  
println	
  sheet.C3.value	
  	
  //=>	
  303.0	
  
println	
  sheet.D4.dateCellValue.format("yyyy-­‐MM-­‐dd")	
  //=>	
  2015-­‐02-­‐29	
  
//	
  指定した矩形内でイテレーション	
  
sheet.A1_D4.each	
  {	
  row	
  -­‐>	
  
	
  	
  	
  	
  println	
  row	
  
}	
  
//=>	
  [[A1の値,	
  B1の値,	
  301.0,	
  42041.0],	
  
//	
  	
  	
  	
  [A2の値,	
  B2の値,	
  302.0,	
  42042.0],	
  
//	
  	
  	
  	
  [A3の値,	
  B3の値,	
  303.0,	
  42043.0],	
  
//	
  	
  	
  	
  [A4の値,	
  B4の値,	
  304.0,	
  42044.0]]
日付型のセルはプログラマが日付であるこ
とを意識して取得しなければならない
テンプレートエンジン
例えば
定型レポートをテンプレートから生成する
何らかの定義情報を元に、ソースコードを生成する
テンプレートエンジン?
複数行文字列リテラル+ String#stripMargin()
SimpleTemplateEngine
複数行文字列リテラル+stripMargin()
String	
  applyTemplate(name,	
  title)	
  {	
  
	
  	
  	
  	
  return	
  """	
  
	
  	
  	
  	
  	
  	
  	
  	
  |こんにちは、${name}さん	
  
	
  	
  	
  	
  	
  	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  	
  |本日は、${title}をご案内させていただきます。	
  
	
  	
  	
  	
  	
  	
  	
  	
  |...	
  
	
  	
  	
  	
  	
  	
  	
  	
  |""".stripMargin()	
  
}	
  
println	
  applyTemplate("日本	
  太郎",	
  "プログラミングGROOVY")	
  
//=>	
  こんにちは、日本	
  太郎さん	
  
//	
  
//	
  	
  	
  本日は、プログラミングGROOVYをご案内させていただきます。	
  
//	
  	
  	
  ...
先頭行のエスケープ付き改行と
stripMarginを使うことで、
インデントを自然な形に えられる
SimpleTemplateEngine
import	
  groovy.text.SimpleTemplateEngine	
  
String	
  applyTemplate(name,	
  title)	
  {	
  
	
  	
  	
  	
  String	
  templateText	
  =	
  '''	
  
	
  	
  	
  	
  	
  	
  	
  	
  |こんにちは、${name}さん	
  
	
  	
  	
  	
  	
  	
  	
  	
  |	
  
	
  	
  	
  	
  	
  	
  	
  	
  |本日は、<%=	
  title	
  %>をご案内させていただきます。	
  
	
  	
  	
  	
  	
  	
  	
  	
  |...	
  
	
  	
  	
  	
  	
  	
  	
  	
  |'''.stripMargin()	
  
	
  	
  	
  	
  def	
  template	
  =	
  new	
  SimpleTemplateEngine().createTemplate(templateText)	
  
def	
  binding	
  =	
  [name:	
  name,	
  title:	
  title]	
  
return	
  template.make(binding)	
  
}	
  
println	
  applyTemplate("日本	
  太郎",	
  "プログラミングGROOVY")	
  
//=>	
  こんにちは、日本	
  太郎さん	
  
//	
  
//	
  	
  	
  本日は、プログラミングGROOVYをご案内させていただきます。	
  
//	
  	
  	
  ...
JSP形式の変数展開もできる
テンプレート文字列を外部ファイ
ルから読み込むようにすると良い
(例)new File("template.tpl").text
#ccc_g4 でGradleからの利用例が紹介されたらしい?
(再掲)Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
万が一時間があれば紹介したい
Javaから
Groovyを使う
例えば
システムにプラグイン機構を追加する
頻繁に変更されるビジネスロジック部分をGroovyス
クリプトとして外だしする
アプリの一部だけでも良いからGroovyで書きたい
JavaからGroovyを使う
Groovyで実装したクラスをJavaから利用する
コンパイルしたクラスを同梱する
Groovyのコンパイルには、groovycコマンドやGradleを使う
クラスパスにgroovy-all.jarが含まれてさえいれば、普通に使える
Groovyソースコードから動的にクラスをロードする
groovy-all.jarはもちろん必要
GroovyスクリプトをJavaから動的に実行する(CGI風)
GroovyShell
ちょっとスクリプトを実行するぐらいの用途ならば手軽で便利
GroovyScriptEngine
対象ディレクトリを事前指定するため、複数のGroovyスクリプト
を取り扱うようなプラグイン機構などに向いている
コンパイルしたクラスを同梱する
コンパイルしたGroovyのクラスがクラス
パスに通っていれば、普通に使える
Groovyソースコードから動的にクラスをロードする
GroovyClassLoaderを使うと、Groovyソースコード
から実行時に動的にクラスロードできる
GroovyスクリプトをJavaから実行する: GroovyShell
Bindingというマップ的なオブジェクト
を利用して、スクリプト上で利用可能
な暗黙変数を渡すことができる
GroovyスクリプトをJavaから実行する: GroovyScriptEngine
スクリプトのルートディレクトリ
をあらかじめ指定しておく
まとめ
Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
というわけで、まずはこの辺から始めてみませんか?
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムのプラグイン機構/拡張ポイント
Javaから外部のGroovyスクリプトを簡単に実行できる
Jenkins
プロジェクトの開発支援スクリプト
DBのセットアップ、Excel操作等
これもおすすめ
参考情報
プログラミングGroovy
Java技術者を対象に、
Groovyの基本から応用
までを丁寧に説明して
います
対象のGroovyバージョ
ンが1.8とだいぶ古いの
ですが、記載されてい
る内容はほとんど陳腐
化してないので、今で
もお勧めの一冊
http://gihyo.jp/book/2011/978-4-7741-4727-7
Gradle徹底入門
2014/11発売
世界に現存するGradle
本の中でここまで突っ
込んで説明したものは
ほぼないレベル
分厚いですが、その分
情報がたっぷりです
(私もレビュアで参加)
http://www.shoeisha.co.jp/book/detail/9784798136431
その他、参考URL
サンプルコード
https://github.com/nobeans/jjug-ccc-2015-
spring-groovy
Groovy Home
http://groovy-lang.org/
Groovy JDK
http://docs.groovy-lang.org/docs/latest/
html/groovy-jdk/
Groovy 演算子オーバロード
http://groovy-lang.org/
operators.html#Operator-Overloading
GVM
http://gvmtool.net/
GroovyServ
http://kobo.github.io/groovyserv/
GExcelAPI
https://github.com/nobeans/gexcelapi
NekoHTML
http://nekohtml.sourceforge.net/
jsoup
http://jsoup.org/
プログラミングGROOVY別冊:第8章 Groovy
2.0の新機能
http://beta.mybetabook.com/showpage/
506162510cf2ffb79bb046b1
実用的なGroovy: Javaアプリケーションに
Groovyを混ぜ込む
http://www.ibm.com/developerworks/jp/
java/library/j-pg05245/
Embedding Groovy(JavaからGroovyを使
う)
http://groovy.codehaus.org/Embedding
+Groovy
Groovyの使いどころ∼7つの導入パターン∼
http://www.slideshare.net/nobeans/the-
report-of-javaone2011-about-groovy



Java開発の強力な相棒として今すぐ使えるGroovy
Yasuharu Nakano / @nobeans
2015-04-11
JJUG CCC 2015 Spring #ccc_g6

Java開発の強力な相棒として今すぐ使えるGroovy