More Related Content Similar to Java x Groovy: improve your java development life (20) More from Uehara Junji (20) Java x Groovy: improve your java development life1. Java x Groovyで
開発効率を高めよう
Java Developer Workshop #2
日本Grails Groovyユーザ会
上原 潤二
2011.12.1
2011年12月1日木曜日
2. 自己紹介
上原潤二(@uehaj)
NTTソフトウェア株式会社
JGGUG運営委員
プログラミングGROOVY(技術評
論社)共著
Grails徹底入門(翔泳社)共著
ブログ「Grな日々」
GroovyServ, LispBuilder, GVM
開発者
2011年12月1日木曜日
3. 本日皆さんに伝えたいこと
Groovyとは何か?
Groovyは簡単なのか?
Groovyは便利なのか?
JavaプログラマにとってGroovyと
は何か?
3
2011年12月1日木曜日
4. Groovyとは何か
Java VM上で動作する動的なスクリプト言語
構文はJavaと 上位互換
ほぼ
プラットフォームやセキュリティモデルは全く
同じ
ユニークな特徴:
Javaと共存・併用するための言語
主要開発者はVMWare社(Spring Source)に所属
4
2011年12月1日木曜日
5. コード例1: HelloWorld.java __
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
5
2011年12月1日木曜日
6. コード例1: HelloWorld.groovy
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
6
2011年12月1日木曜日
7. コード例1: HelloWorld.groovy
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
Javaソースコードの拡張子.java
を.groovyに変更するだけで
groovyコードとして実行できる。
6
2011年12月1日木曜日
9. コード例1: hello.groovy
println "hello world"
Groovyでは以下が省略可能:
main,クラス定義,文末のセミコロ
ン, System.out,メソッド呼び出し
の括弧,(例外宣言,静的型宣言,
import宣言) etc..
7
2011年12月1日木曜日
12. Groovyは何で無いか
別言語をJVMにポーティングしたもので
はない
➡JVM以外では動かない
8
2011年12月1日木曜日
13. Groovyは何で無いか
別言語をJVMにポーティングしたもので
はない
➡JVM以外では動かない
Next Javaではない
8
2011年12月1日木曜日
14. Groovyは何で無いか
別言語をJVMにポーティングしたもので
はない
➡JVM以外では動かない
Next Javaではない
➡Javaを駆逐しない・パラダイムシフトしない
8
2011年12月1日木曜日
15. Groovyは何で無いか
別言語をJVMにポーティングしたもので
はない
➡JVM以外では動かない
Next Javaではない
➡Javaを駆逐しない・パラダイムシフトしない
過去のOSSプロジェクトではない
8
2011年12月1日木曜日
16. Groovyは何で無いか
別言語をJVMにポーティングしたもので
はない
➡JVM以外では動かない
Next Javaではない
➡Javaを駆逐しない・パラダイムシフトしない
過去のOSSプロジェクトではない
➡活発な開発と意欲的な機能拡張が続いている
8
2011年12月1日木曜日
18. Groovyの特徴4つ
Javaと親和性
簡潔 が高い
本日は上記2つの特徴を中心に紹介し
ます。
高機能 柔軟
10
2011年12月1日木曜日
19. 簡潔
11
http://www.flickr.com/photos/dan_culleton/4905300673/
2011年12月1日木曜日
20. 例:ワードカウント処理
テキストファイル中の単語の出現回数
を数える
$ cat input.txt
That that is is that that is
not is not is that it it is
$ java WordCount input.txt
1: That
2: not
2: it
4: that
6: is
12
2011年12月1日木曜日
21. ワードカウント処理(Java)
import java.util.Comparator; Object[] list = entrySet.toArray();
import java.util.HashMap; Comparator comp = new Comparator(){
import java.util.Map; public int compare(Object o1, Object o2)
import java.util.Set; {
import java.util.List; Map.Entry<String, Integer> e1 =
import java.util.Arrays; (Map.Entry<String, Integer>) o1;
import java.io.FileReader; Map.Entry<String, Integer> e2 =
import java.io.BufferedReader; (Map.Entry<String, Integer>) o2;
import java.io.FileNotFoundException; return e1.getValue() - e2.getValue();
import java.io.IOException; }
};
public class WordCount { Arrays.sort(list, comp);
@SuppressWarnings(value = "unchecked") for (Object it: list) {
public static void main(String[] args) { Map.Entry<String, Integer> entry =
FileReader fis = null; (Map.Entry<String, Integer>)it;
BufferedReader br = null; System.out.println(entry.getValue() + ":
try { "+entry.getKey());
HashMap<String, Integer> map = new }
HashMap<String, Integer>(); }
fis = new FileReader(args[0]); catch (IOException e) {
br = new BufferedReader(fis); try {if (br != null) br.close();}catch
String line; (IOException ioe){}
while ((line = br.readLine()) != null) { try {if (fis != null)fis.close();}catch
for (String it: line.split("W+")) { (IOException ioe){}
map.put(it, (map.get(it)==null) ? 1 : e.printStackTrace();
(map.get(it) + 1)); }
} }
}
Set<Map.Entry<String, Integer>> entrySet =
} 48行
map.entrySet();
13
2011年12月1日木曜日
22. ワードカウント処理(Groovy)
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
println "${it.value}: ${it.key}"
}
4行
14
2011年12月1日木曜日
23. .text
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
.getText()の略記法
println "${it.value}: ${it.key}"
}
File#getText()はJava APIに
対して追加されたGDKメソッド
ファイル内容の全体を1つの
Stringとして返す
2011年12月1日木曜日
24. GDKメソッド
Java標準APIクラスにメソッドを追加
java.lang.Stringを例にとると、
Java標準APIは、65個メソッド
GDKでは、91個のメソッド追加
asType(Class c) execute(List envp, getAt(Collection padLeft(Number replaceFirst(Pattern toInteger()
bitwiseNegate() File dir) indices) numberOfChars) pattern, Closure toList()
capitalize() expand() getChars() padRight(Number closure) toLong()
center(Number expand(int tabStop) isAllWhitespace() numberOfChars, reverse() toSet()
numberOfChars, expandLine(int isBigDecimal() String padding) size() toShort()
String padding) tabStop) isBigInteger() padRight(Number split() toURI()
center(Number find(String regex) isCase(Object numberOfChars) splitEachLine(String toURL()
numberOfChars) find(Pattern pattern) switchValue) plus(Object value) regex, Closure tokenize(String
contains(String text) find(String regex, isDouble() previous() closure) token)
count(String text) Closure closure) isFloat() readLines() splitEachLine tokenize(Character
decodeBase64() find(Pattern pattern, isInteger() replaceAll(Pattern (Pattern pattern, token)
denormalize() Closure closure) isLong() pattern, String Closure closure) tokenize()
eachLine(Closure findAll(String regex) isNumber() replacement) stripIndent() tr(String sourceSet,
closure) findAll(Pattern leftShift(Object replaceAll(String stripIndent(int String
eachLine(int pattern) value) regex, Closure numChars) replacementSet)
firstLine, Closure findAll(String regex, matches(Pattern closure) stripMargin() unexpand()
closure) Closure closure) pattern) replaceAll(Pattern stripMargin(String unexpand(int
eachMatch(String findAll(Pattern minus(Object target) pattern, Closure marginChar) tabStop)
regex, Closure pattern, Closure multiply(Number closure) stripMargin(char unexpandLine(int
closure) closure) factor) replaceFirst(Pattern marginChar) tabStop)
eachMatch(Pattern getAt(int index) next() pattern, String toBigDecimal()
pattern, Closure getAt(IntRange normalize() replacement) toBigInteger()
closure) range) padLeft(Number replaceFirst(String toBoolean()
execute() getAt(EmptyRange numberOfChars, regex, Closure toCharacter()
execute(String[] range) String padding) closure) toDouble()
envp, File dir) getAt(Range range) toFloat()
16
2011年12月1日木曜日
25. GDKメソッド
Java標準APIクラスにメソッドを追加
java.lang.Stringを例にとると、
Java標準APIは、65個メソッド
GDKでは、91個のメソッド追加
asType(Class c) execute(List envp, getAt(Collection padLeft(Number replaceFirst(Pattern toInteger()
bitwiseNegate() File dir) indices) numberOfChars) pattern, Closure toList()
capitalize() expand() getChars() padRight(Number closure) toLong()
center(Number expand(int tabStop) isAllWhitespace() numberOfChars, reverse() toSet()
“ls”.execute()
numberOfChars,
String padding)
center(Number
expandLine(int
tabStop)
find(String regex)
isBigDecimal()
isBigInteger()
isCase(Object
String padding)
padRight(Number
numberOfChars)
size()
split()
splitEachLine(String
toShort()
toURI()
toURL()
" lsコマンドを実行(Processが返る)
numberOfChars) find(Pattern pattern) switchValue) plus(Object value) regex, Closure tokenize(String
contains(String text) find(String regex, isDouble() previous() closure) token)
count(String text) Closure closure) isFloat() readLines() splitEachLine tokenize(Character
decodeBase64() find(Pattern pattern, isInteger() replaceAll(Pattern (Pattern pattern, token)
denormalize() Closure closure) isLong() pattern, String Closure closure) tokenize()
eachLine(Closure findAll(String regex) isNumber() replacement) stripIndent() tr(String sourceSet,
closure) findAll(Pattern leftShift(Object replaceAll(String stripIndent(int String
eachLine(int pattern) value) regex, Closure numChars) replacementSet)
firstLine, Closure findAll(String regex, matches(Pattern closure) stripMargin() unexpand()
closure) Closure closure) pattern) replaceAll(Pattern stripMargin(String unexpand(int
eachMatch(String findAll(Pattern minus(Object target) pattern, Closure marginChar) tabStop)
regex, Closure pattern, Closure multiply(Number closure) stripMargin(char unexpandLine(int
closure) closure) factor) replaceFirst(Pattern marginChar) tabStop)
eachMatch(Pattern getAt(int index) next() pattern, String toBigDecimal()
pattern, Closure getAt(IntRange normalize() replacement) toBigInteger()
closure) range) padLeft(Number replaceFirst(String toBoolean()
execute() getAt(EmptyRange numberOfChars, regex, Closure toCharacter()
execute(String[] range) String padding) closure) toDouble()
envp, File dir) getAt(Range range) toFloat()
16
2011年12月1日木曜日
26. GDKメソッド
Java標準APIクラスにメソッドを追加
java.lang.Stringを例にとると、
Java標準APIは、65個メソッド
GDKでは、91個のメソッド追加
asType(Class c) execute(List envp, getAt(Collection padLeft(Number replaceFirst(Pattern toInteger()
bitwiseNegate() File dir) indices) numberOfChars) pattern, Closure toList()
capitalize() expand() getChars() padRight(Number closure) toLong()
center(Number expand(int tabStop) isAllWhitespace() numberOfChars, reverse() toSet()
“ls”.execute()
numberOfChars,
String padding)
center(Number
expandLine(int
tabStop)
find(String regex)
isBigDecimal()
isBigInteger()
isCase(Object
String padding)
padRight(Number
numberOfChars)
size()
split()
splitEachLine(String
toShort()
toURI()
toURL()
" lsコマンドを実行(Processが返る)
numberOfChars) find(Pattern pattern) switchValue) plus(Object value) regex, Closure tokenize(String
contains(String text) find(String regex, isDouble() previous() closure) token)
count(String text) Closure closure) isFloat() readLines() splitEachLine tokenize(Character
decodeBase64() find(Pattern pattern, isInteger() replaceAll(Pattern (Pattern pattern, token)
denormalize() Closure closure) isLong() pattern, String Closure closure) tokenize()
eachLine(Closure findAll(String regex) isNumber() replacement) stripIndent() tr(String sourceSet,
closure) findAll(Pattern leftShift(Object replaceAll(String stripIndent(int String
eachLine(int pattern) value) regex, Closure numChars) replacementSet)
firstLine, Closure findAll(String regex, matches(Pattern closure) stripMargin() unexpand()
closure) Closure closure) pattern) replaceAll(Pattern stripMargin(String unexpand(int
“あいうえお”.tr(“あ-ん”,”ア-ン”)
eachMatch(String
regex, Closure
closure)
findAll(Pattern
pattern, Closure
closure)
minus(Object target)
multiply(Number
factor)
pattern, Closure
closure)
replaceFirst(Pattern
marginChar)
stripMargin(char
marginChar)
tabStop)
unexpandLine(int
tabStop)
eachMatch(Pattern getAt(int index) next() pattern, String toBigDecimal()
" “アイウエオ”
pattern, Closure getAt(IntRange normalize() replacement) toBigInteger()
closure) range) padLeft(Number replaceFirst(String toBoolean()
execute() getAt(EmptyRange numberOfChars, regex, Closure toCharacter()
execute(String[] range) String padding) closure) toDouble()
envp, File dir) getAt(Range range) toFloat()
16
2011年12月1日木曜日
27. .split(/正規表現/)
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
println "${it.value}: ${it.key}"
} /∼/は文字列定数の記法。ただし
文字’’を特別扱いしない
“W” == /W/
Java APIの
String#split(String)
2011年12月1日木曜日
28. .countBy{}
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
println "${it.value}: ${it.key}"
} countByはコレクション・イテレータに対
して追加されたGDKメソッド
分類基準に基づいて要素をグルーピングし
た上でグループごとの要素数をカウントする
2011年12月1日木曜日
29. .countBy{}
リスト
“ABC” “ABC” “DEF” “GHI” “ABC” “GHI”
countBy{it}
分類基準をクロージャで与える
マップ
“ABC” : 3 “DEF” : 1 “GHI” : 2
コレクションやイテレータに対してcountByを適用する
と、分類基準で分類されたグループをキー、そのグループの
要素数をバリューとするマップが得られる。(c.f. groupBy)
19
2011年12月1日木曜日
30. .entrySet().sort{}
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
println "${it.value}: ${it.key}"
} entrySet()はJava API
sortはクロージャで比較するソート(GDKメ
ソッド)
2011年12月1日木曜日
31. each, GString
def words = new File(args[0]).text.split(/W+/)
words.countBy{it}.entrySet().sort{it.value}.each {
println "${it.value}: ${it.key}"
}
eachはそれぞれに対して処理(クロージャ)
文字列中の$変数名、${ブロック}はその値
に置換される(GString)
21
2011年12月1日木曜日
33. 短かさの意味
Javaに比してコード量は1/5∼1/3
短かければ良いわけではない
短くて分かりにくくなることもある
重要なのは「やりたい事(what)/コード量」
のSN比
23
2011年12月1日木曜日
34. これは何でしょう?
Set<Map.Entry<String, Integer>> entrySet =
import java.util.Comparator; map.entrySet();
import java.util.HashMap; Object[] list = entrySet.toArray();
import java.util.Map; Comparator comp = new Comparator(){
import java.util.Set; public int compare(Object o1, Object o2) {
import java.util.List; Map.Entry<String, Integer> e1 =
import java.util.Arrays; (Map.Entry<String, Integer>) o1;
import java.io.FileReader; Map.Entry<String, Integer> e2 =
import java.io.BufferedReader; (Map.Entry<String, Integer>) o2;
import java.io.FileNotFoundException; return e1.getValue() - e2.getValue();
import java.io.IOException; }
};
public class WordCount { Arrays.sort(list, comp);
@SuppressWarnings(value = "unchecked") for (Object it: list) {
public static void main(String[] args) { Map.Entry<String, Integer> entry =
FileReader fis = null; (Map.Entry<String, Integer>)it;
BufferedReader br = null; System.out.println(entry.getValue() + ":
try { ["+entry.getKey()+"]");
HashMap<String, Integer> map = new }
HashMap<String, Integer>(); }
fis = new FileReader(args[0]); catch (IOException e) {
br = new BufferedReader(fis); try {if (br != null) br.close();}catch
String line; (IOException ioe){}
while ((line = br.readLine()) != null) { try {if (fis != null)fis.close();}catch
for (String it: line.split("s+")) { (IOException ioe){}
map.put(it, (map.get(it)==null) ? 1 : e.printStackTrace();
(map.get(it) + 1)); }
} }
} }
24
2011年12月1日木曜日
35. これは何でしょう?
Set<Map.Entry<String, Integer>> entrySet =
import java.util.Comparator; map.entrySet();
import java.util.HashMap; Object[] list = entrySet.toArray();
import
import 答:Java版ワードカウントから「処理
java.util.Map;
java.util.Set;
Comparator comp = new Comparator(){
public int compare(Object o1, Object o2) {
import java.util.List; Map.Entry<String, Integer> e1 =
の記述」を抜き出したもの。
import java.util.Arrays; (Map.Entry<String, Integer>) o1;
import java.io.FileReader; Map.Entry<String, Integer> e2 =
import java.io.BufferedReader; (Map.Entry<String, Integer>) o2;
import java.io.FileNotFoundException; return e1.getValue() - e2.getValue();
import java.io.IOException; }
};
public class WordCount { Arrays.sort(list, comp);
@SuppressWarnings(value = "unchecked") for (Object it: list) {
public static void main(String[] args) { Map.Entry<String, Integer> entry =
FileReader fis = null; (Map.Entry<String, Integer>)it;
BufferedReader br = null; System.out.println(entry.getValue() + ":
try { ["+entry.getKey()+"]");
HashMap<String, Integer> map = new }
HashMap<String, Integer>(); }
fis = new FileReader(args[0]); catch (IOException e) {
br = new BufferedReader(fis); try {if (br != null) br.close();}catch
String line; (IOException ioe){}
while ((line = br.readLine()) != null) { try {if (fis != null)fis.close();}catch
for (String it: line.split("s+")) { (IOException ioe){}
map.put(it, (map.get(it)==null) ? 1 : e.printStackTrace();
(map.get(it) + 1)); }
} }
} }
24
2011年12月1日木曜日
36. 短かさの効用
Groovyの記述レベルは人間の認知
レベルでの「やって欲しいこと」の
記述に近い
➡理解性向上
➡リファクタリングの頻度減少
25
2011年12月1日木曜日
38. Java親和性(1):文法
正しいJavaコードは、正しいGroovyコード
(ほぼ上位互換)
以下を含めて
アノテーション,enum, Generics
Java7機能(一部未対応)
27
2011年12月1日木曜日
39. Java親和性(2):API
Java APIをそのままもしくは拡張して使う
例えばGroovy独自のコレクションクラス
群というものはない
GDK(Groovy Development Kit)
Java APIにメソッドを追加
28
2011年12月1日木曜日
40. Java親和性(3):相互運用
Groovyコードは常にJavaクラスに変換された上
で実行される。(次項)
Java VMから見てGroovyコードは普通のJava
クラス
ラッパークラスは無い
スクリプト(mainメソッドやクラス定義がな
いGroovyコード)も内部的にクラスが生成さ
れて実行される
29
2011年12月1日木曜日
41. Javaコードの実行
Javaソース
javac
.classファイル
javaコマンド
JVM
標準クラスローダ
Javaクラス
30
2011年12月1日木曜日
42. Groovyコードの実行
Javaソース Groovyコード
javac
.classファイル
javaコマンド groovyコマンド
JVM
標準クラスローダ Groovyクラスローダ
(オンメモリ実行時コンパイラ)
Javaクラス Javaクラス
31
2011年12月1日木曜日
43. Groovyコードの実行
Javaソース Groovyコード
javac groovyc
.classファイル .classファイル
javaコマンド groovyコマンド
JVM
標準クラスローダ Groovyクラスローダ
(オンメモリ実行時コンパイラ)
Javaクラス Javaクラス Javaクラス
31
2011年12月1日木曜日
44. Groovyコードの実行
Javaソース Groovyコード
javac groovyc
.classファイル .classファイル
javaコマンド groovyコマンド
JVM
標準クラスローダ Groovyクラスローダ
(オンメモリ実行時コンパイラ)
Javaクラス Javaクラス Javaクラス
31 呼び出し・継承自由
2011年12月1日木曜日
45. Java開発への取り込み方
7つの利用パターンを元にして
http://www.flickr.com/photos/holeymoon/1634408365/
32
2011年12月1日木曜日
46. Groovy「7つの利用パターン」
by Dierk König
万能接着剤(Super Glue): Javaのコンポーネントやフレームワークを
Groovyを糊(glue)としてつなぐ
やわらかな心臓部(Liquid Heart): 中核となるロジックだけをGroovy/
DSLで書けるようにする
お化粧(Lipstick): Javaのライブラリを簡潔に利用できる層をもうけ
る。
内視鏡手術(Keyhole Surgery): 実行時にGroovyスクリプトを接続で
きる小さな口を用意しておく
無制限の開放(Unlimited Openness): 全部Groovyで書く
小人さんスクリプト(House-elf Script): 周辺の各種支援スクリプト
をGroovyで書く
ゴーストライター(Ghost Writer): 裏でコード生成
33
2011年12月1日木曜日
47. Groovyの利用パターン(1 of 7)
万能接着剤(Super Glue): Javaのコンポーネントやフレー
ムワークをGroovyが糊(glue)としてつなぐ
Groovy
Java Java Java
JavaAPI
Java VM
34
2011年12月1日木曜日
48. 万能接着剤(Super Glue)の例
やりたいこと:
指定ファイルをbzip2圧縮して
httpファイルアップロード
Groovy
ant HttpUnit
35
2011年12月1日木曜日
49. ant+HtmlUnit
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')
import com.gargoylesoftware.htmlunit.WebClient;
new AntBuilder().bzip2(src:args[0], zipfile:args[0]+".bz2")
def url = "http://pukiwiki.example.com/index.php?
plugin=attach&pcmd=upload&page=test"
def page = new WebClient().getPage(url)
def fileField = page.getElementById('_p_attach_file')
fileField.valueAttribute = args[0]+".bz2"
page.getByXPath("//input[@value='アップロード']")[0].click()
36
2011年12月1日木曜日
50. ant+HtmlUnit
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')
import com.gargoylesoftware.htmlunit.WebClient;
new AntBuilder().bzip2(src:args[0], zipfile:args[0]+".bz2")
def url = "http://pukiwiki.example.com/index.php?
plugin=attach&pcmd=upload&page=test"
def page = new WebClient().getPage(url)
def fileField = page.getElementById('_p_attach_file')
fileField.valueAttribute = args[0]+".bz2"
page.getByXPath("//input[@value='アップロード']")[0].click()
依存ライブ
ラリの実行時
自動取得
36
2011年12月1日木曜日
51. ant+HtmlUnit
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')
import com.gargoylesoftware.htmlunit.WebClient;
new AntBuilder().bzip2(src:args[0], zipfile:args[0]+".bz2")
def url = "http://pukiwiki.example.com/index.php?
plugin=attach&pcmd=upload&page=test"
def page = new WebClient().getPage(url)
def fileField = page.getElementById('_p_attach_file')
fileField.valueAttribute = args[0]+".bz2"
page.getByXPath("//input[@value='アップロード']")[0].click()
Java資産の有 依存ライブ
効活用 ラリの実行時
(HtmlUnit, Ant) 自動取得
36
2011年12月1日木曜日
52. @Grab/Grape
@Grab('net.sourceforge.htmlunit:htmlunit:2.8')
import com.gargoylesoftware.htmlunit.WebClient;
group指定 module指定 versoin指定
Grape
Groovyスクリプト用の依存Jar管理機構
Apache Ivyベース/Maven互換
スクリプトを初回実行時に依存jarを自
動ダウンロード
37
2011年12月1日木曜日
53. Groovyの利用パターン (2 of 7)
やわらかな心臓部(Liquid Heart): 中核となるロジックだ
けをGroovy/DSLで書けるようにする
頻繁な変更
Groovy/DSL
Java
JavaAPI
Java VM
38
2011年12月1日木曜日
54. やわらかな心臓部(LiquidHeart)の例
JavaからGroovyを呼びだす
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
File script = new File(filename);
shell.evaluate(script);
39
2011年12月1日木曜日
55. Groovyの利用パターン (3 of 7)
お化粧(Lipstick): Javaのライブラリ・コンポーネントを
簡潔に利用できる層をもうける。
Groovy
Wrapper
Javaコンポーネント
JavaAPI
Java VM
2011年12月1日木曜日
56. お化粧(Lipstick)の例
GroovyFX
JavaFX
Grails
Spring FW Hibernate
Geb Gant/AntBuilder
Selenium Ant
41
2011年12月1日木曜日
57. GroovyFX
Scene Graph DSL: 画面部品のツリー構造を
Groovyのビルダーで記述
new SceneGraphBuilder().
stage(title:"Title",width:400,height:300,visible:true,resizable:true) {
scene(fill: groovyblue) {
rectangle x: 20, y: 20, width: 100, height: 50, fill: blue
onMouseClicked { println "hello" }
}
}
Timeline DSL: 時間軸制御
timeline {
at(2.s) {
change(myCircle, 'layoutX'){ to 500 }
}
}
42
2011年12月1日木曜日
58. Groovyの利用パターン (4 of 7)
内視鏡手術(Keyhole Surgery): 実行時にGroovyスクリ
プトを接続できる小さな口を用意しておく
外部から
Groovyコードを
注入
GroovyShell
Java
JavaAPI
Java VM
43
2011年12月1日木曜日
60. Groovyの利用パターン (6 of 7)
小人さんスクリプト(House-elf Script): 周辺の各種支援
スクリプトをGroovyで書く
周辺スクリプト
開発対象のシステム
Java Groovy
JavaAPI JavaAPI
Java VM Java VM
1 45
2011年12月1日木曜日
61. Groovyの利用パターン (7 of 7)
ゴーストライター(Ghost Writer): 裏でコード生成
Groovyコード
自動生成されるバイトコード
JavaAPI
Java VM
1 32
46
2011年12月1日木曜日
62. ゴーストライターの例
やりたいこと:イミュータブル(不変)クラスを定
義しよう!
クラスはfinalに
全フィールドをfinalかつprivate
getter定義
Mutableなフィールド (配列やStringBufferや
Dateなど) の取得に対しては「防御的コピー」
全フィールドをコンストラクタで初期化するコン
ストラクタを定義
フィールドの値に基づくequals, hashCode,
toStringを定義する
参考: Effective Java (2nd Edition), p73: Item15 Minimize
mutability
2011年12月1日木曜日
63. Java版 イミュータブルクラス: 57行
public final class Person { if (getClass() != obj.getClass())
private final String firstName; return false;
private final String lastName; Person other = (Person) obj;
if (firstName == null) {
public Person(String firstName, String lastName) { if (other.firstName != null)
this.firstName = firstName; return false;
this.lastName = lastName; } else if (!firstName.equals(other.firstName))
} return false;
if (lastName == null) {
public String getFirstName() { if (other.lastName != null)
return firstName; return false;
} } else if (!lastName.equals(other.lastName))
return false;
public String getLastName() { return true;
return lastName; }
}
@Override
@Override public String toString() {
public int hashCode() { return "Person(firstName:" + firstName
final int prime = 31; + ", lastName:" + lastName + ")";
int result = 1; }
result = prime * result + ((firstName == null)
? 0 : firstName.hashCode()); }
result = prime * result + ((lastName == null)
? 0 : lastName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
やすく、
if (this == obj)
、ミスが混入し
return true;
作成が大変 はない
ド上明確で
if (obj == null)
return false;
意図がコー
参考: http://groovy.codehaus.org/Immutable+AST+Macro
48
2011年12月1日木曜日
64. Groovy版イミュータブルクラス: 4行
これ
だけ
です
@Immutable よ!こ
れだ
class Person { け
String firstName, lastName
}
49
2011年12月1日木曜日
65. Groovy版イミュータブルクラス: 4行
これ
だけ
です
@Immutable よ!こ
れだ
class Person { け
String firstName, lastName
}
x = new Person("Junji","Uehara")
assert x.lastName == "Uehara"
x.firstName = "abc"
//==>
groovy.lang.ReadOnlyPropertyException:
Cannot set readonly property: firstName
for class: Person
49
2011年12月1日木曜日
66. 強力なゴースト執筆陣
@Immutable, @ListenerList, @ToString,
@Equals, @EqualsAndHashcode,
@AutoClone, @TimedInterrupt, @Lazy,
@Mixin, @Singleton,
@InheritConsructors,@WithReadLock,
@WithWriteLock, @Log, @Delegate,
@Lazy, @Singleton, @Bindable, ほか
上記は「AST変換」を起動するアノテーション。
50
2011年12月1日木曜日
68. Groovy 2.0へ
安定版最新
Groovy 1.8.4
開発版最新
Groovy 2.0.0-beta1 (=1.9-beta5相当)
2012年初頭に正式版登場予定
52
2011年12月1日木曜日
69. Groovyの新機能
Java 7のProject Coin対応(2.0以降)
二進リテラル
リテラル中の下線
マルチキャッチ
InvokeDynamic対応(2.0以降)
try-with-resourceなどはいまのところ未
Groovy自体のモジュール化(1.8以降)
静的型チェック(2.0.0 beta1で実験的実装)
静的コンパイル(2.0以降)
53
2011年12月1日木曜日
70. まとめ
http://www.flickr.com/photos/limonada/214375219/
54
2011年12月1日木曜日
71. 本日伝えたかったこと
Groovyとは何か?
Groovyは簡単なのか?
Java開発者にとってYES!
通常のJava開発と地続き
Groovyは便利なのか?
Java開発者にとってYES! 簡潔さと高機能さが
今、手はいる。
JavaプログラマにとってGroovyとは何か?
Java x Groovyを実現するもの!
55
2011年12月1日木曜日
72. 本日伝えたかったこと
Groovyとは何か?
Groovyは簡単なのか?
Java開発者にとってYES!
通常のJava開発と地続き
Groovyは便利なのか?
Java開発者にとってYES! 簡潔さと高機能さが
今、手はいる。
JavaプログラマにとってGroovyとは何か?
Java x Groovyを実現するもの!
55
2011年12月1日木曜日
73. 本日伝えたかったこと
Groovyとは何か?
Groovyは簡単なのか?
Java開発者にとってYES!
通常のJava開発と地続き
Groovyは便利なのか?
Java開発者にとってYES! 簡潔さと高機能さが
今、手はいる。
JavaプログラマにとってGroovyとは何か?
Java x Groovyを実現するもの!
55
2011年12月1日木曜日
74. 本日伝えたかったこと
Groovyとは何か?
Groovyは簡単なのか?
Java開発者にとってYES!
通常のJava開発と地続き
Groovyは便利なのか?
Java開発者にとってYES! 簡潔さと高機能さが
今、手はいる。
JavaプログラマにとってGroovyとは何か?
Java x Groovyを実現するもの!
55
2011年12月1日木曜日
75. Java x Groovy
GroovyはJavaの弱点を補う
組み合わせて使うことで相乗効果を発揮
Java開発者にとって修得・導入がごく容易
Java x Groovy
(DIxAOP的な意味で)
Groovy利用をJava開発と組み合わせることで、
Java開発を加速する!
56
2011年12月1日木曜日
77. コミュニティもよろしく
活発な国内コミュニティ
電子雑誌 G*マガジン
月1定例勉強会 G*ワークショップ
年1恒例合宿
その他企画
58
2011年12月1日木曜日