Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
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界隈...
in Java
//	
  HelloWorld.java	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  main(...
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  m...
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  m...
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  m...
in Groovy
//	
  HelloWorld.groovy	
  
public	
  class	
  HelloWorld	
  {	
  
	
  	
  	
  	
  public	
  static	
  void	
  m...
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	
 ...
静的型付けサポート
Groovy 2.0から静的型付けのための機能が追加
@TypeChecked
コンパイル時に静的に型チェックする
ただし、実行時は動的型付けのまま
@CompileStatic
静的にコンパイルする
実行時に動的型付けによ...
Java言語との密な関係
Java(7以前)との文法の互換性が高い
Java開発者なら非常にとっつきやすい
ただし、Java 8のラムダ記法は未対応
代わりにクロージャを使う
すべてのJava APIがシームレスに呼び出せる
標準API、サード...
Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムの...
Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
システムの...
Groovy入門
その前にまずは
Javaとの文法の違い
Javaとの文法の違い
セミコロンは省略可能
returnも省略可能
チェック例外のthrows宣言も省略可能
型宣言も省略可能
プリミティブ型はラッパー型
各種リテラル
数値/文字列/リスト/マップ
アクセス修飾子
メソッド呼び出し
セミコロンは省略可能
//	
  セミコロンは不要	
  
int	
  a	
  =	
  1	
  
//	
  セミコロンはあってもOKだが、付けない方がお勧め	
  
int	
  b	
  =	
  2;
returnも省略可能
String	
  hello()	
  {	
  
	
  	
  	
  	
  //	
  returnは省略できる	
  
	
  	
  	
  	
  //	
  Ruby等と同様に最後に評価された値が返る	...
チェック例外のthrows宣言も省略可能
String	
  doWithoutThrows()	
  {	
  
	
  	
  	
  	
  throw	
  new	
  Exception("チェック例外!")	
  
}	
  
t...
型宣言も省略可能
def	
  キーワード
Object型の別名として宣言時に使える



以下の場合、型宣言自体を省略可能(→Object型)
メソッドや変数で、privateやstaticなどの修飾子が1つ以上ある場合
メソッドの仮引数
f...
プリミティブ型で宣言しても実体はラッパー型
ただし、nullは代入不可能
また、最適化機構により、可能な場合において内部的に
もプリミティブ型のまま扱われる場合もある
プリミティブ型はラッパー型
assert	
  1.getClass()	
...
リテラル:数値
Groovyの浮動小数リテラルはBigDecimal型
桁あふれや誤差を気にしないで演算できる
プリミティブ型のように通常の中置演算子が使える
assert	
  5.3.getClass()	
  ==	
  java.mat...
リテラル:文字列
//	
  基本はJavaと同じくダブルクォーテーション	
  
println	
  "Hello,	
  World!"	
  	
  //=>	
  Hello,	
  World!	
  
//	
  ${}によって変...
リテラル:文字列
//	
  トリプル「ダブルクォート」(ややこしい)	
  
//	
  改行や単体のクォート文字列自体を含められる(GString型)	
  
//	
  トリプル「シングルクォート」にすると単なるString型になる(展開...
リテラル:文字列
//	
  開始行の行末エスケープとString#stripMargin()を使うと、	
  
//	
  いい感じにインデントできて、読みやすい	
  
def	
  s	
  =	
  "Third"	
  
printl...
リテラル:文字列
//	
  スラッシュクォート	
  
//	
  単体バックスラッシュを特殊文字として扱わないため、エスケープが不要。	
  
//	
  正規表現をシンプルに書ける	
  
assert	
  (/This	
  is	
...
リテラル:リスト
//	
  専用リテラルの導入により、シンプルにリストを記述できる	
  
def	
  l	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
assert	
  l.size()	
  ==	
...
(参考)リテラル:セット
//	
  セット専用のリテラルはないが、asによる型変換で表現できる	
  
def	
  s	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  as	
  Set	
  
assert	...
リテラル:マップ
//	
  専用リテラルの導入により、シンプルにマップを記述できる	
  
def	
  m	
  =	
  ['a':	
  1,	
  'b':	
  2,	
  'c':	
  3]	
  
assert	
  m.si...
アクセス修飾子
アクセス修飾子は基本的に飾りです
privateメンバにもアクセスできる
IDEなどで一応警告が出るぐらい
無印=public
パッケージプライベートは存在しない
一応、アノテーションで強引に宣言できる
@PackageScop...
メソッド呼び出し
//	
  引数の丸括弧が省略できる	
  
println("Hello")	
  
println	
  "Hello"	
  
//	
  引数がない場合は省略できない	
  
println()	
  
メソッド呼び出し
def	
  hello()	
  {	
  
	
  	
  	
  	
  "Hello!"	
  
}	
  
//	
  Stringでメソッド名を指定できる	
  
assert	
  "hello"()	
  ==...
メソッド呼び出し
//	
  名前付き引数?	
  
def	
  hello(Map	
  map)	
  {	
  
	
  	
  	
  	
  "Hello,	
  ${map.name}${map.period}"	
  
}	
 ...
メソッド呼び出し
//	
  引数のデフォルト値	
  
def	
  bye(name	
  =	
  "World")	
  {	
  
	
  	
  	
  	
  "Good-­‐bye,	
  ${name}."	
  
}	
  ...
コンストラクタ呼び出し
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  a	
  
	
  	
  	
  	
  String	
  b	
  
	
  	
  	
  	
  int	
...
Groovyの各種機能
クロージャ
他言語の第1級関数オブジェクトやクロージャと同等
JavaScript, Ruby, Perl, Lisp, ....
第一級オブジェクトとして、変数に代入したり引数
に渡したりできる
高階関数
無名内部クラスやJava 8のラムダ...
クロージャ:定義と実行
//	
  クロージャを定義する	
  
Closure	
  c	
  =	
  {	
  
	
  	
  	
  	
  return	
  "Hello,	
  Closure!"	
  
}	
  
//	
 ...
クロージャ:クロージャでの引数の受け取り
//	
  引数なし	
  
def	
  c0	
  =	
  {-­‐>	
  
	
  	
  	
  	
  "Hello,	
  Closure!"	
  
}	
  
assert	
  c...
クロージャ:クロージャを引数として渡す
//	
  渡されたクロージャを指定されたnameで実行するだけのメソッド	
  
def	
  justDoIt(String	
  name,	
  Closure	
  closure)	
  {	...
(参考)クロージャ:高階関数とレキシカルスコープの例
def	
  createIdGenerator(prefix)	
  {	
  	
  //	
  この実引数と	
  
	
  	
  	
  	
  int	
  counter	
 ...
assertキーワード/Power Assert
Spockから正式採用したPower Assertが使える
Spockの方が更に先に進んでいて若干高機能(適合率を表示するとか)
Assertion	
  failed:	
  	
  
ass...
Groovy JDK/GDK
GroovyがJavaの標準APIに追加した便利なAPI群
Javaの不便な点をAPIレベルで改善できる
printlnもObjectに実装されたGDK APIのひとつ
System.out.printlnに委譲し...
GDKの例
//	
  Groovy本家サイトのHTMLを表示する	
  
println	
  new	
  URL("http://groovy-­‐lang.org/").getText()	
  
//	
  ファイルの中身を表示する	...
コレクション操作
各種の内部イテレーション記法が使える
外部イテレーション
forやiteratorなどで外側から要素を回す
内部イテレーション
各要素に適用すべき処理をクロージャ/ラムダなどでコレク
ションに渡して、コレクション自体が内部でル...
コレクション操作:リスト
List	
  l	
  =	
  [1,	
  2,	
  3,	
  4,	
  5]	
  
//	
  各要素に対してクロージャの処理を適用する	
  
l.each	
  {	
  number	
  -­‐...
コレクション操作:マップ
Map	
  m	
  =	
  [a:	
  1,	
  b:	
  2,	
  c:	
  3]	
  
//	
  クロージャ引数を1つだけ宣言すると、Map.Entryが受け取れる	
  
m.each	
  ...
デフォルトimport済みパッケージ
高頻度で使うこれらのパッケージはデフォルトでimport済み
java.lang.*	
  
java.io.*	
  
java.net.*	
  
java.util.*	
  
groovy.lang...
GroovyBeans
JavaBeansに対するGroovyの強化サポート
プロパティに対するgetter/setterの自動生成
class	
  Book	
  {	
  
	
  	
  	
  	
  String	
  title	...
GroovyBeans
class	
  GroovyBeansSample	
  {	
  
	
  	
  	
  	
  public	
  String	
  p	
  =	
  "PUBLIC"	
  
	
  	
  	
  	
 ...
GroovyBeans
プロパティアクセスの簡略記法
class	
  Book	
  {	
  
	
  	
  	
  	
  String	
  title	
  
}	
  
def	
  book	
  =	
  new	
  Boo...
Grape
Mavenリポジトリから直接Jarをダウンロードし、
クラスパスに通してからスクリプトを実行できる
ダウンロードしたファイルは $HOME/.groovy/grapes
配下に格納される
@Grab('org.apache.comm...
便利な演算子
等値演算子 ==
Javaではインスタンスの同一性のための使うが、Groovyではequals呼び出
しになっている
Stringの比較で普通に==が使える!
インスタンス同一性のチェックにはObject#is()を使う
エルビス...
レンジ(範囲)
範囲を表すコレクション
groovy.lang.Range
始点と終点を指定してその間の要素をIterableに扱う
for	
  (int	
  i	
  :	
  1..9)	
  {	
  //	
  閉区間(9を含む)	...
正規表現サポート
正規表現をサポートする演算子やリテラルがある
//	
  「==~」完全一致によるマッチング結果の真偽値を返す	
  
assert	
  	
  	
  	
  "abc"	
  ==~	
  /a.c/	
  
asser...
論理値/Groovy Truth
Groovyではboolean/Boolean以外の値についても、
真偽判定できる
assert	
  !	
  0	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
 ...
演算子オーバーロード
GroovyではJavaと同等の各種演算子が使える
実は、それぞれの演算子は対応する特定のメソッド呼び出しに変換されている
つまり、演算子オーバロードが可能
GDKでも多数活用されている
例えば、「+」→「plus()」、...
AST変換
抽象構文木(Abstract Syntax Tree)レベルでのコード変換技術
コンパイルの過程で、アノテーションでマーキングした対象箇所に、
任意のコードの追加・置換ができる
Groovyシンタックスの意味自体を改変する「グローバ...
AST変換: @Grabと@Log
//	
  Mavenセントラルリポジトリからダウンロード&クラスパスに指定	
  
@Grab("log4j:log4j")	
  
import	
  groovy.util.logging.Log4j	...
AST変換: @Singleton
@groovy.lang.Singleton	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  value	
  
}	
  
//	
  インスタ...
AST変換: @Immutable
@groovy.transform.Immutable	
  
class	
  Sample	
  {	
  
	
  	
  	
  	
  String	
  value	
  
}	
  
def	
...
AST変換: @ToString, @EqualsAndHashCode, @TupleConstructors
@groovy.transform.TupleConstructor	
  
@groovy.transform.ToString...
静的Groovy
@TypeChecked
コンパイル時に静的型チェックする
lintのようなもの
実行時はいつも通り動的に
@CompileStatic
指定した範囲を静的型付けとしてコンパイルする
実行時も静的に(性能的に有利)
Groov...
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  
	
...
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  	
 ...
静的Groovy: @TypeChecked
class	
  MyList	
  {	
  
	
  	
  	
  	
  private	
  List<String>	
  list	
  =	
  []	
  
	
  	
  	
 ...
静的Groovy: 非@CompileStatic
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
  if	
  (n	
  <	
  2)	
  return	
  1	
  
	
  	
  	...
静的Groovy: @CompileStatic
import	
  groovy.transform.CompileStatic	
  
@CompileStatic	
  
long	
  fib(long	
  n)	
  {	
  
	...
(参考)AST変換: @Memoized
import	
  groovy.transform.Memoized	
  
@Memoized	
  
long	
  fib(long	
  n)	
  {	
  
	
  	
  	
  	
 ...
Groovy
コードの実行
実行可能なコード形式
実行可能なコード形式
Groovyプログラムとして実行可能なのは...
mainメソッド持つクラス(Javaと同等)
Groovyスクリプト
JUnitのテストケース
Runnableの実装クラス
mainメソッド持つクラス
//	
  in	
  HelloMain.groovy	
  
class	
  HelloMain	
  {	
  
	
  	
  	
  	
  static	
  void	
  main(String.....
Groovyスクリプト
//	
  in	
  hello.groovy	
  
println	
  "Hello,	
  Script!"	
  
//=>	
  Hello,	
  Script!
クラスの外側のルートレベルで直接コード
...
JUnitのテストケース
//	
  in	
  HelloTest.groovy	
  
import	
  junit.framework.TestCase	
  
class	
  HelloTest	
  extends	
  Test...
Runnableの実装クラス
//	
  in	
  HelloRunnable.groovy	
  
class	
  HelloRunnable	
  implements	
  Runnable	
  {	
  
	
  	
  	
  ...
実行可能なコード形式
Groovyプログラムとして実行可能なのは...
mainメソッド持つクラス(Javaと同等)
Groovyスクリプト
JUnitのテストケース
Runnableの実装クラス
今回のケースでは
とりあえず、これで十分
実行方法
各種実行方法
groovy
java -jar groovy-all.jar
groovyc + java
groovyConsole
groovysh
GroovyServ
スクリプト起動の高速化
Groovy Web Console
htt...
各種実行方法
groovy
java -jar groovy-all.jar
groovyc + java
groovyConsole
groovysh
GroovyServ
スクリプト起動の高速化
Groovy Web Console
htt...
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
シ...
開発支援ツールとしての活用
Groovyは、たとえ対象システムの開発言語として採
用しない場合でも、Javaによる開発を支援するツー
ルとして非常に有用
な
るほ
ど
ね
Java APIのお試し
例えば
標準APIを試す
○○の場合はどういう動作をするんだったっけ?
正規表現はこれで良いのかな?
初めて使うサードパーティ製のライブラリを試す
お試し環境
groovyConsole上で試す
シンプルなエディタで試行錯誤できる
Grapeを使ってサードパーティライブラリも試せる
わかりやすくてお手軽
groovyshで試す
JavaとGroovyの標準APIであれば、Tabによるコード...
groovyConsoleの例
XMLのパース
例えば
設定ファイル内容の一覧を出力する
JUnitのテストレポートをパースして自動的に進 報
告資料に追加する
Rest APIの結果をチェックする
XmlParser/XmlSlurper
Groovy標準APIのXmlParserが便利
兄弟分として XmlSlurper(∼すらーぱー)がある
XmlParser:DOM的(インメモリ、変更可能)
XmlSlurper:SAX的(ストリー...
XMLParserで属性やテキストを参照する例
def	
  inputXml	
  =	
  """	
  
<root>	
  
	
  	
  <items>	
  
	
  	
  	
  	
  <item	
  id="1"	
  ...
HTML/XMLの出力
例えば
自動的に収集した情報を元にHTMLレポートを出力
する
システムにインポートするXMLファイルを生成する
MarkupBuilder
Groovy標準APIのMarkupBuilderが便利
タグでマークアップされたテキストを生成する
波括弧のブロックで階層構造を表現できる
if文やループ制御構文が使える
マップの情報を元にHTMLを出力する例
def	
  generateHtml	
  =	
  {	
  data,	
  writer	
  -­‐>	
  
	
  	
  def	
  reportTitle	
  =	
  '試験実施日...
マップの情報を元にHTMLを出力する例
	
  	
  //...	
  
	
  	
  new	
  groovy.xml.MarkupBuilder(writer).html	
  {	
  
	
  	
  	
  	
  head	
...
MarkupBuilderについてもう少し補足
def	
  builder	
  =	
  new	
  groovy.xml.MarkupBuilder()	
  
def	
  existMethod(a)	
  {	
  "EXIST_...
HTMLスクレイピング
例えば
定期レポートのための情報を収集する
開発中のWebアプリのテストの一環として、ある画
面のHTMLを取得して、内容をチェックする
HTMLスクレイピング
URL#getText()
HTMLテキストを取得すればいい場合は一番簡単
XmlParser/XmlSlurper
整形式であるXHMLの場合は単品でOK
非整形式のHTMLの場合はNekoHTMLを併用すればOK
h...
HTMLスクレイピング: URL#getText()
String	
  html	
  =	
  new	
  URL("http://groovy-­‐lang.org/").text	
  
//	
  1行ずつチェックしてURLをパース...
HTMLスクレイピング: XmlParser + NekoHTML
@Grab('net.sourceforge.nekohtml:nekohtml:1.9.21')	
  
import	
  org.cyberneko.html.parse...
HTMLスクレイピング: jsoup
@Grab('org.jsoup:jsoup:1.8.1')	
  
import	
  org.jsoup.Jsoup	
  
import	
  org.jsoup.nodes.Document	
  ...
Groovy SQLによる
RDBMS操作
例えば
テスト用ダミーデータをDBに大量投入する
定期レポートのための情報を収集する
保守のためデータベースの内容を定期的に監視する
あるシステムから別のシステムにデータを移行する
Groovy SQL
Groovy標準APIのGroovy SQLが便利
クエリ発行と結果のResultSetからの値の取り出しなど
が簡単に実行できる
DataSetを使うと、コレクション操作のようにレコード
の追加やイテレーションが実行できる
Groovy SQLでH2を操作する
@Grab('com.h2database:h2')	
  
@GrabConfig(systemClassLoader=true)	
  //	
  JDBCはシステムクラスローダから探されるので必要	
...
DataSetを使う例
@Grab('com.h2database:h2')	
  
@GrabConfig(systemClassLoader=true)	
  //	
  JDBCはシステムクラスローダから探されるので必要	
  
impo...
GExcelAPIによる
Excel操作
例えば
ダミーデータの定義表として読み込む
Excelデータから特定セルの値を読み込んで集計する
コード生成の入力データとして
GExcelAPI
https://github.com/nobeans/gexcelapi
Apache POIのGroovy風ラッパーライブラリ
POIを直接使った場合、セルを特定するイ
ンデックス指定がとても分かりづらい
GExcelAP...
GExcelAPI
@GrabResolver(name="bintray",	
  root="http://dl.bintray.com/nobeans/maven")	
  
@Grab("org.jggug.kobo:gexcelapi...
テンプレートエンジン
例えば
定型レポートをテンプレートから生成する
何らかの定義情報を元に、ソースコードを生成する
テンプレートエンジン?
複数行文字列リテラル+ String#stripMargin()
SimpleTemplateEngine
複数行文字列リテラル+stripMargin()
String	
  applyTemplate(name,	
  title)	
  {	
  
	
  	
  	
  	
  return	
  """	
  
	
  	
  	
  	
...
SimpleTemplateEngine
import	
  groovy.text.SimpleTemplateEngine	
  
String	
  applyTemplate(name,	
  title)	
  {	
  
	
  	...
(再掲)Groovyの使いどころ
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Framework
シ...
Javaから
Groovyを使う
例えば
システムにプラグイン機構を追加する
頻繁に変更されるビジネスロジック部分をGroovyス
クリプトとして外だしする
アプリの一部だけでも良いからGroovyで書きたい
JavaからGroovyを使う
Groovyで実装したクラスをJavaから利用する
コンパイルしたクラスを同梱する
Groovyのコンパイルには、groovycコマンドやGradleを使う
クラスパスにgroovy-all.jarが含まれてさえ...
コンパイルしたクラスを同梱する
コンパイルした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
システムの...
というわけで、まずはこの辺から始めてみませんか?
メインのプログラミング言語
Grails/Spring Boot/Vert.x/Android
設定ファイルの記述言語(as DSL)
Gradle/Spring Boot/Spring Fra...
参考情報
プログラミングGroovy
Java技術者を対象に、
Groovyの基本から応用
までを丁寧に説明して
います
対象のGroovyバージョ
ンが1.8とだいぶ古いの
ですが、記載されてい
る内容はほとんど陳腐
化してないので、今で
もお勧めの一...
Gradle徹底入門
2014/11発売
世界に現存するGradle
本の中でここまで突っ
込んで説明したものは
ほぼないレベル
分厚いですが、その分
情報がたっぷりです
(私もレビュアで参加)
http://www.shoeisha.co.j...
その他、参考URL
サンプルコード
https://github.com/nobeans/jjug-ccc-2015-
spring-groovy
Groovy Home
http://groovy-lang.org/
Groovy JDK
h...
Java開発の強力な相棒として今すぐ使えるGroovy
Yasuharu Nakano / @nobeans
2015-04-11
JJUG CCC 2015 Spring #ccc_g6
Próxima SlideShare
Cargando en…5
×

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

24.584 visualizaciones

Publicado el

Presentation slide of my session of Groovy at JJUG CCC 2015 Spring

Publicado en: Tecnología
  • Inicia sesión para ver los comentarios

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

  1. 1. Yasuharu Nakano / @nobeans Java開発の強力な相棒として今すぐ使える 2015-04-11 JJUG CCC 2015 Spring #ccc_g6
  2. 2. 中野 靖治 @nobeans 所属:NTTソフトウェア株式会社 Grails推進室 職業:Grails Advocate
  3. 3. 概要
  4. 4. Groovyとは Javaをもっとすごくしたもの 「ポストJava」ではなく「Java強化外骨格」もしくは 「Java拡張パック」のイメージ Java VM上で動作する動的型付け言語 Rubyによく似た文法を持ち、生産性が高い Groovy界隈はRubyへのリスペクト成分が高め Grailsの旧名「Groovy on Rails」 2003年生まれ(平成生まれ)
  5. 5. in Java //  HelloWorld.java   public  class  HelloWorld  {          public  static  void  main(String...  args)  {                  System.out.println("Hello,  World!");          }   }   //=>  Hello,  World!
  6. 6. in Groovy //  HelloWorld.groovy   public  class  HelloWorld  {          public  static  void  main(String...  args)  {                  System.out.println("Hello,  World!");          }   }   //=>  Hello,  World! Groovyとしてもvalidなコードなので 拡張子を変えるだけでOK
  7. 7. in Groovy //  HelloWorld.groovy   public  class  HelloWorld  {          public  static  void  main(String...  args)  {                  System.out.println("Hello,  World!");          }   }   //=>  Hello,  World! セミコロンは省略可能
  8. 8. in Groovy //  HelloWorld.groovy   public  class  HelloWorld  {          public  static  void  main(String...  args)  {                  System.out.println("Hello,  World!")          }   }   //=>  Hello,  World! Object#println()が使える(GDKのひとつ)
  9. 9. in Groovy //  HelloWorld.groovy   public  class  HelloWorld  {          public  static  void  main(String...  args)  {                  println("Hello,  World!")          }   }   //=>  Hello,  World! スクリプト形式で実行可能(クラスが不要)
  10. 10. in Groovy //  HelloWorld.groovy   println("Hello,  World!")   //=>  Hello,  World! メソッド呼び出しの丸括弧は省略可能
  11. 11. in Groovy //  HelloWorld.groovy   println  "Hello,  World!"   //=>  Hello,  World!
  12. 12. 動的型付け言語 Groovyは基本的に動的型付け言語
  13. 13. 動的型付けの例 Integer  num  =  "Hello"   //=>  GroovyCastException:  Cannot  cast  object  'Hello'   with  class  'java.lang.String'  to  class   'java.lang.Integer' groovycでコンパイルには成功する しかし、実行すると例外が発生する
  14. 14. 静的型付けサポート Groovy 2.0から静的型付けのための機能が追加 @TypeChecked コンパイル時に静的に型チェックする ただし、実行時は動的型付けのまま @CompileStatic 静的にコンパイルする 実行時に動的型付けによる機構は使われない Javaとほぼ同等レベルの性能に(理論上) どちらもクラス単位、メソッド単位で指定できる ただし、明示的な型指定が省略できない 動的を前提とした一部の機能も使えなくなる http://beta.mybetabook.com/showpage/508402720cf2ffb79bb046db
  15. 15. Java言語との密な関係 Java(7以前)との文法の互換性が高い Java開発者なら非常にとっつきやすい ただし、Java 8のラムダ記法は未対応 代わりにクロージャを使う すべてのJava APIがシームレスに呼び出せる 標準API、サードパーティのクラスもすべて普通に使える 更に「Groovy JDK(GDK)」と呼ばれる超便利メソッ ド群が標準クラスに追加されている! コンパイルするとclassファイルになる 最低限、Java VMとgroovy-all.jarだけあれば実行できる
  16. 16. Groovyの使いどころ メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等
  17. 17. Groovyの使いどころ メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等 今日は後半でこの辺を中心に紹介します
  18. 18. Groovy入門 その前にまずは
  19. 19. Javaとの文法の違い
  20. 20. Javaとの文法の違い セミコロンは省略可能 returnも省略可能 チェック例外のthrows宣言も省略可能 型宣言も省略可能 プリミティブ型はラッパー型 各種リテラル 数値/文字列/リスト/マップ アクセス修飾子 メソッド呼び出し
  21. 21. セミコロンは省略可能 //  セミコロンは不要   int  a  =  1   //  セミコロンはあってもOKだが、付けない方がお勧め   int  b  =  2;
  22. 22. returnも省略可能 String  hello()  {          //  returnは省略できる          //  Ruby等と同様に最後に評価された値が返る      "Hello"   }   assert  hello()  ==  "Hello"
  23. 23. チェック例外のthrows宣言も省略可能 String  doWithoutThrows()  {          throw  new  Exception("チェック例外!")   }   try  {          doWithoutThrows()          assert  false   }  catch  (Exception  e)  {          assert  e.getMessage()  ==  "チェック例外!"   } throwsがなくてもOK!
  24. 24. 型宣言も省略可能 def  キーワード Object型の別名として宣言時に使える
 
 以下の場合、型宣言自体を省略可能(→Object型) メソッドや変数で、privateやstaticなどの修飾子が1つ以上ある場合 メソッドの仮引数 final  helloPrefix  =  "Hello,  "   public  hello(name)  {        def  message  =  helloPrefix  +  name        return  message   } 省略はできるが、ドキュメンテーションとして考えると、公開APIのシグネチャで は型を明記する方が好ましい def  hoge  =  "ほげ"
  25. 25. プリミティブ型で宣言しても実体はラッパー型 ただし、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'.
  26. 26. リテラル:数値 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話がありましたね
  27. 27. リテラル:文字列 //  基本は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!"
  28. 28. リテラル:文字列 //  トリプル「ダブルクォート」(ややこしい)   //  改行や単体のクォート文字列自体を含められる(GString型)   //  トリプル「シングルクォート」にすると単なるString型になる(展開無し)   def  s  =  "Third"   println  """First,   "Second",   ${s}.   """   //=>   //  First,   //  "Second",   //  Third. ヒアドキュメント風に使える
  29. 29. リテラル:文字列 //  開始行の行末エスケープとString#stripMargin()を使うと、   //  いい感じにインデントできて、読みやすい   def  s  =  "Third"   println  """          |First,          |"Second",          |${s}.          |""".stripMargin()   //=>   //  First,   //  "Second",   //  Third. GDKのString#stripMargin()と合わせて使 うとインデントもいい感じにできる
  30. 30. リテラル:文字列 //  スラッシュクォート   //  単体バックスラッシュを特殊文字として扱わないため、エスケープが不要。   //  正規表現をシンプルに書ける   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:  /" 正規表現を書くときは断然コレ
  31. 31. リテラル:リスト //  専用リテラルの導入により、シンプルにリストを記述できる   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]
  32. 32. (参考)リテラル:セット //  セット専用のリテラルはないが、asによる型変換で表現できる   def  s  =  [1,  2,  3,  4,  5]  as  Set   assert  s.size()  ==  5   assert  s.getClass()  ==  java.util.LinkedHashSet  
  33. 33. リテラル:マップ //  専用リテラルの導入により、シンプルにマップを記述できる   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          //  プロパティアクセス風
  34. 34. アクセス修飾子 アクセス修飾子は基本的に飾りです privateメンバにもアクセスできる IDEなどで一応警告が出るぐらい 無印=public パッケージプライベートは存在しない 一応、アノテーションで強引に宣言できる @PackageScope   基本は無印(public)でよい その他、ドキュメンテーション目的として... クラス内部だけで利用するものにprivateを付けたり 積極的に継承を想定しているものにprotectedを付けたり
  35. 35. メソッド呼び出し //  引数の丸括弧が省略できる   println("Hello")   println  "Hello"   //  引数がない場合は省略できない   println()  
  36. 36. メソッド呼び出し def  hello()  {          "Hello!"   }   //  Stringでメソッド名を指定できる   assert  "hello"()  ==  "Hello!"   //  GStringを使ってもOK   def  methodName  =  "hello"   assert  "$methodName"()  ==  "Hello!"
  37. 37. メソッド呼び出し //  名前付き引数?   def  hello(Map  map)  {          "Hello,  ${map.name}${map.period}"   }   assert  hello(period:  "!",  name:  "World")  ==  "Hello,  World!"   //  これの[]を省略できるイメージ   assert  hello([period:  "!",  name:  "World"])  ==  "Hello,  World!"
  38. 38. メソッド呼び出し //  引数のデフォルト値   def  bye(name  =  "World")  {          "Good-­‐bye,  ${name}."   }   assert  bye()  ==  "Good-­‐bye,  World."   assert  bye("Yesterday")  ==  "Good-­‐bye,  Yesterday."
  39. 39. コンストラクタ呼び出し 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>
  40. 40. Groovyの各種機能
  41. 41. クロージャ 他言語の第1級関数オブジェクトやクロージャと同等 JavaScript, Ruby, Perl, Lisp, .... 第一級オブジェクトとして、変数に代入したり引数 に渡したりできる 高階関数 無名内部クラスやJava 8のラムダ記法よりも次の点 で強力 クロージャを宣言した文法上のスコープ(レキシカルス コープ)にある変数(ローカル変数を含む)を参照・変 更できる
  42. 42. クロージャ:定義と実行 //  クロージャを定義する   Closure  c  =  {          return  "Hello,  Closure!"   }   //  実行する   assert  c.call()  ==  "Hello,  Closure!"   //  callを省略することもできる   assert  c()  ==  "Hello,  Closure!"
  43. 43. クロージャ:クロージャでの引数の受け取り //  引数なし   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
  44. 44. クロージャ:クロージャを引数として渡す //  渡されたクロージャを指定された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型であるところがポイント
  45. 45. (参考)クロージャ:高階関数とレキシカルスコープの例 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 が、クロージャごとに個別に管 理されているのがわかる
  46. 46. 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]
  47. 47. 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/
  48. 48. GDKの例 //  Groovy本家サイトのHTMLを表示する   println  new  URL("http://groovy-­‐lang.org/").getText()   //  ファイルの中身を表示する   println  new  File("/my/some.text/").getText()
  49. 49. コレクション操作 各種の内部イテレーション記法が使える 外部イテレーション forやiteratorなどで外側から要素を回す 内部イテレーション 各要素に適用すべき処理をクロージャ/ラムダなどでコレク ションに渡して、コレクション自体が内部でループする GroovyのコレクションAPIは、GDKとして提供されている Java 8のStream APIもこちら
  50. 50. コレクション操作:リスト 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
  51. 51. コレクション操作:マップ 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が用意されている (コレクションの特性上、微妙に品 えは違う)
  52. 52. デフォルト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")
  53. 53. 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へ"
  54. 54. 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" 常に無条件で自動生成するわけではない
  55. 55. 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()
  56. 56. 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を使って即 実行できるスクリプト形式にしている
  57. 57. 便利な演算子 等値演算子 == 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 で紹介されました!
  58. 58. レンジ(範囲) 範囲を表すコレクション 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]
  59. 59. 正規表現サポート 正規表現をサポートする演算子やリテラルがある //  「==~」完全一致によるマッチング結果の真偽値を返す   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
  60. 60. 論理値/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以外は真
  61. 61. 演算子オーバーロード 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"
  62. 62. AST変換 抽象構文木(Abstract Syntax Tree)レベルでのコード変換技術 コンパイルの過程で、アノテーションでマーキングした対象箇所に、 任意のコードの追加・置換ができる Groovyシンタックスの意味自体を改変する「グローバルAST変換」 技術もあるがあまり使われない 例 Grape(@Grab) ロギング(@Log, @Commons, @Log4j, @Slf4j) シングルトン(@Singleton) 不変オブジェクト(@Immutable) 自前クラスの基本要素(@ToString, @EqualsAndHashCode, @Canonical, @InheritConstructors)
  63. 63. 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
  64. 64. 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)
  65. 65. 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  
  66. 66. 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の組み合わせのエイリアス
  67. 67. 静的Groovy @TypeChecked コンパイル時に静的型チェックする lintのようなもの 実行時はいつも通り動的に @CompileStatic 指定した範囲を静的型付けとしてコンパイルする 実行時も静的に(性能的に有利) Groovyの動的な側面に依存した機能が使えない ダックタイピング、privateの呼び出し、など 性能的にカリカリにしたい箇所に、部分的に付けると良い
  68. 68. 静的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に追加する 期待通り動く
  69. 69. 静的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 コンパイル時にエラーが発生する このメソッドを 静的型チェックすると...
  70. 70. 静的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型を明示すると... また動くようになった!
  71. 71. 静的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
  72. 72. 静的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
  73. 73. (参考)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 参照透過な関数の場合、 メモ化(引数と結果の組み合わせ をキャッシュ)の効果が強力に活 用できる場合がある
  74. 74. Groovy コードの実行
  75. 75. 実行可能なコード形式
  76. 76. 実行可能なコード形式 Groovyプログラムとして実行可能なのは... mainメソッド持つクラス(Javaと同等) Groovyスクリプト JUnitのテストケース Runnableの実装クラス
  77. 77. mainメソッド持つクラス //  in  HelloMain.groovy   class  HelloMain  {          static  void  main(String...  args)  {                  println  "Hello,  Main!"          }   }   //=>  Hello,  Main!
  78. 78. 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();   }
  79. 79. 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を用意する必要はない
  80. 80. Runnableの実装クラス //  in  HelloRunnable.groovy   class  HelloRunnable  implements  Runnable  {          void  run()  {                  println  "Hello,  Runnable!"          }   }   //=>  Hello,  Runnable!
  81. 81. 実行可能なコード形式 Groovyプログラムとして実行可能なのは... mainメソッド持つクラス(Javaと同等) Groovyスクリプト JUnitのテストケース Runnableの実装クラス 今回のケースでは とりあえず、これで十分
  82. 82. 実行方法
  83. 83. 各種実行方法 groovy java -jar groovy-all.jar groovyc + java groovyConsole groovysh GroovyServ スクリプト起動の高速化 Groovy Web Console https://groovyconsole.appspot.com/
  84. 84. 各種実行方法 groovy java -jar groovy-all.jar groovyc + java groovyConsole groovysh GroovyServ スクリプト起動の高速化 Groovy Web Console https://groovyconsole.appspot.com/ だいたいこの辺を使っておけばOK
  85. 85. groovyコマンド
  86. 86. java -jar groovy-all.jar == groovyコマンド All-In-OneのJARファイルさえあれば、 groovyコマンドがなくても実行できる!
  87. 87. groovyc + java 滅多に使わない
  88. 88. groovyConsole 編集して、 Ctrl+Rで実行できる 実行結果を表示 Ctrl+Wでクリア 引数なしでもOK
  89. 89. groovysh 限定的ながらも Tabでコード補完ができる
  90. 90. 高速起動 GroovyServ http://kobo.github.io/groovyserv/
  91. 91. Groovy web console クリックで実行 https://groovyconsole.appspot.com/ インストール不要で手軽に試せる
  92. 92. ユースケース
  93. 93. (再掲)Groovyの使いどころ メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等
  94. 94. 開発支援ツールとしての活用 Groovyは、たとえ対象システムの開発言語として採 用しない場合でも、Javaによる開発を支援するツー ルとして非常に有用 な るほ ど ね
  95. 95. Java APIのお試し
  96. 96. 例えば 標準APIを試す ○○の場合はどういう動作をするんだったっけ? 正規表現はこれで良いのかな? 初めて使うサードパーティ製のライブラリを試す
  97. 97. お試し環境 groovyConsole上で試す シンプルなエディタで試行錯誤できる Grapeを使ってサードパーティライブラリも試せる わかりやすくてお手軽 groovyshで試す JavaとGroovyの標準APIであれば、Tabによるコード補完 が効く点でちょっと便利 エディタ+groovy (or GroovyServ) エディタの機能ですぐに実行できる環境をつくると便利 (例)vim + quickrun.vim + GroovyServ http://nobeans.hatenablog.com/entry/20111024/1319435155 ちなみに、この資料のサンプルコードは ほとんどgroovyConsoleで書きました
  98. 98. groovyConsoleの例
  99. 99. XMLのパース
  100. 100. 例えば 設定ファイル内容の一覧を出力する JUnitのテストレポートをパースして自動的に進 報 告資料に追加する Rest APIの結果をチェックする
  101. 101. XmlParser/XmlSlurper Groovy標準APIのXmlParserが便利 兄弟分として XmlSlurper(∼すらーぱー)がある XmlParser:DOM的(インメモリ、変更可能) XmlSlurper:SAX的(ストリーム処理、参照専用) 細かい点で差異はあるものの、シンプルな参照に限定し たAPIの使い勝手はほぼ同じ メモリ展開が難しい巨大なファイルを対象とするのでな ければ、XmlParserを選択しておけばOK
  102. 102. 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などのコレクション操作が そのまま適用できる
  103. 103. HTML/XMLの出力
  104. 104. 例えば 自動的に収集した情報を元にHTMLレポートを出力 する システムにインポートするXMLファイルを生成する
  105. 105. MarkupBuilder Groovy標準APIのMarkupBuilderが便利 タグでマークアップされたテキストを生成する 波括弧のブロックで階層構造を表現できる if文やループ制御構文が使える
  106. 106. マップの情報を元に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)   }
  107. 107. マップの情報を元に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)      }  }  }  }  }      //...
  108. 108. 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)をトリガ にして構造をビルドしていくクラスになっている
  109. 109. HTMLスクレイピング
  110. 110. 例えば 定期レポートのための情報を収集する 開発中のWebアプリのテストの一環として、ある画 面のHTMLを取得して、内容をチェックする
  111. 111. HTMLスクレイピング URL#getText() HTMLテキストを取得すればいい場合は一番簡単 XmlParser/XmlSlurper 整形式であるXHMLの場合は単品でOK 非整形式のHTMLの場合はNekoHTMLを併用すればOK http://nekohtml.sourceforge.net/ jsoup jQuery風のセレクタAPIが使える http://jsoup.org/
  112. 112. 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  }
  113. 113. 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  }
  114. 114. 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  }
  115. 115. Groovy SQLによる RDBMS操作
  116. 116. 例えば テスト用ダミーデータをDBに大量投入する 定期レポートのための情報を収集する 保守のためデータベースの内容を定期的に監視する あるシステムから別のシステムにデータを移行する
  117. 117. Groovy SQL Groovy標準APIのGroovy SQLが便利 クエリ発行と結果のResultSetからの値の取り出しなど が簡単に実行できる DataSetを使うと、コレクション操作のようにレコード の追加やイテレーションが実行できる
  118. 118. 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]
  119. 119. 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)
  120. 120. GExcelAPIによる Excel操作
  121. 121. 例えば ダミーデータの定義表として読み込む Excelデータから特定セルの値を読み込んで集計する コード生成の入力データとして
  122. 122. GExcelAPI https://github.com/nobeans/gexcelapi Apache POIのGroovy風ラッパーライブラリ POIを直接使った場合、セルを特定するイ ンデックス指定がとても分かりづらい GExcelAPIを使うと、Excelのセルラベルで ある「A1」でアクセスできる!
  123. 123. 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]] 日付型のセルはプログラマが日付であるこ とを意識して取得しなければならない
  124. 124. テンプレートエンジン
  125. 125. 例えば 定型レポートをテンプレートから生成する 何らかの定義情報を元に、ソースコードを生成する
  126. 126. テンプレートエンジン? 複数行文字列リテラル+ String#stripMargin() SimpleTemplateEngine
  127. 127. 複数行文字列リテラル+stripMargin() String  applyTemplate(name,  title)  {          return  """                  |こんにちは、${name}さん                  |                  |本日は、${title}をご案内させていただきます。                  |...                  |""".stripMargin()   }   println  applyTemplate("日本  太郎",  "プログラミングGROOVY")   //=>  こんにちは、日本  太郎さん   //   //      本日は、プログラミングGROOVYをご案内させていただきます。   //      ... 先頭行のエスケープ付き改行と stripMarginを使うことで、 インデントを自然な形に えられる
  128. 128. 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からの利用例が紹介されたらしい?
  129. 129. (再掲)Groovyの使いどころ メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等 万が一時間があれば紹介したい
  130. 130. Javaから Groovyを使う
  131. 131. 例えば システムにプラグイン機構を追加する 頻繁に変更されるビジネスロジック部分をGroovyス クリプトとして外だしする アプリの一部だけでも良いからGroovyで書きたい
  132. 132. JavaからGroovyを使う Groovyで実装したクラスをJavaから利用する コンパイルしたクラスを同梱する Groovyのコンパイルには、groovycコマンドやGradleを使う クラスパスにgroovy-all.jarが含まれてさえいれば、普通に使える Groovyソースコードから動的にクラスをロードする groovy-all.jarはもちろん必要 GroovyスクリプトをJavaから動的に実行する(CGI風) GroovyShell ちょっとスクリプトを実行するぐらいの用途ならば手軽で便利 GroovyScriptEngine 対象ディレクトリを事前指定するため、複数のGroovyスクリプト を取り扱うようなプラグイン機構などに向いている
  133. 133. コンパイルしたクラスを同梱する コンパイルしたGroovyのクラスがクラス パスに通っていれば、普通に使える
  134. 134. Groovyソースコードから動的にクラスをロードする GroovyClassLoaderを使うと、Groovyソースコード から実行時に動的にクラスロードできる
  135. 135. GroovyスクリプトをJavaから実行する: GroovyShell Bindingというマップ的なオブジェクト を利用して、スクリプト上で利用可能 な暗黙変数を渡すことができる
  136. 136. GroovyスクリプトをJavaから実行する: GroovyScriptEngine スクリプトのルートディレクトリ をあらかじめ指定しておく
  137. 137. まとめ
  138. 138. Groovyの使いどころ メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等
  139. 139. というわけで、まずはこの辺から始めてみませんか? メインのプログラミング言語 Grails/Spring Boot/Vert.x/Android 設定ファイルの記述言語(as DSL) Gradle/Spring Boot/Spring Framework システムのプラグイン機構/拡張ポイント Javaから外部のGroovyスクリプトを簡単に実行できる Jenkins プロジェクトの開発支援スクリプト DBのセットアップ、Excel操作等 これもおすすめ
  140. 140. 参考情報
  141. 141. プログラミングGroovy Java技術者を対象に、 Groovyの基本から応用 までを丁寧に説明して います 対象のGroovyバージョ ンが1.8とだいぶ古いの ですが、記載されてい る内容はほとんど陳腐 化してないので、今で もお勧めの一冊 http://gihyo.jp/book/2011/978-4-7741-4727-7
  142. 142. Gradle徹底入門 2014/11発売 世界に現存するGradle 本の中でここまで突っ 込んで説明したものは ほぼないレベル 分厚いですが、その分 情報がたっぷりです (私もレビュアで参加) http://www.shoeisha.co.jp/book/detail/9784798136431
  143. 143. その他、参考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
 

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

×