Groovy
「GroovyはJavaの拡張ライブラリといえる」(テストコードで利用)
★Javaと違ったところ
if文では、「0やnullはfalse、それ以外はtrue」と判断
セミコロン、returnキーワードは省略可
thisキーワードはstaticメソッドの中でも使える(クラス自身を指す)
メソッドとクラスはデフォルトでpublic
protected はJavaにおけるpackage-protectedとprotectedの両方に相当
チェック例外と非チェック例外の区別がない
未定義のメンバを使ったり、間違った型の引数を渡したりしてもJavaのようにコンパイルエラーが起こらない
★Javaにはないところ
クロージャ
リストやマップのためのネイティブ構文
GroovyMarkupおよびGPathのサポート
正規表現のネイティブサポート
ポリモルフィックな イテレーション(繰り返し)と強力な switch文
動的および静的型付けのサポート(メソッド、フィールド、変数の型宣言は省略可)
文字列の中に式を埋め込むこと
JDKに追加された新しいヘルパーメソッド
Beansのプロパティやイベントリスナの追加を書くためのよりシンプルな構文
?.演算子を使った安全なナビゲーション
★デフォルトのimport
java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.*
★基本
Groovy Java
等値性 a == b a.equals(b)
同一性 a.is(b) a == b
print 'Hello, Groovy!' // 改行なし
println 'Hello, Groovy!' // 改行あり
printf 'Hello, %s', 'Groovy!' // 整形
for文
for (int i =0; i < len; i++)
for (i in 0..len-1)
for (i in 0..<len)
for ( i in [0, 1, 2, 3, 4] )
for ( i in (0..4).toArray() )
def map = ['a':1, 'b':2, 'c':3]
x = 0
for ( e in map ) {
x += e.value
}
assert x == 6
或いは
x = 0
for ( v in map.values() ) {
x += v
}
assert x == 6
def text = "abc"
def list = []
for (c in text) {
list.add(c)
}
assert list == ["a", "b", "c"]
switch文
def x = 1.23
def result = ""
switch ( x ) {
case "foo":
result = "found"
break
case [4, 5, 6, 'inList']:
result = "list"
break
case 12..30:
result = "range"
break
case Integer:
result = "integer"
break
case Number:
result = "number"
break
default:
result = "default"
}
assert result == "number"
★オープンクラス
obj = new Expando()
obj.name = "Andy"
obj.message = "Hello"
obj.say = {
name = it
println message + name
}
obj.say("Robby")
★文字列
def msg = "Hello"
msg -= "l"
msg *= 3
println msg //HeloHeloHelo
def text = "nice!"
def x = text[2]
assert x == "c"
assert x.class == String
def sub = text[1..3]
assert sub == 'ice'
def x = text[-1]
assert x == "!"
def name = text[3..1]
assert name == "eci"
★Closure
msg = { println "Hello ${it}!" }
或いは
msg = {str -> println "Hello ${str}!" }
msg('Andy')
total = 0
(1..100).each { total += it }
或いは
total = 0
n = 1
(100).times { total += n++ }
def add = { x, y -> x + y }
def mult = { x, y -> x * y }
def min = { x, y -> [x,y].min() }
def max = { x, y -> [x,y].max() }
def do(list, Closure invoke) {
if (list.size() < 2) return []
def next = invoke(list[0], list[1])
return [next] + pairWise(list[1..-1], invoke)
}
assert do(1..5, add) == [3,5,7,9]
assert do(1..5, mult) == [2,6,12,20]
assert do(1..5, min) == [1,2,3,4]
assert do(1..5, max) == [2,3,4,5]
assert 'dcba-abcd' == ['a','b','c','d'].inject('-'){
result, item -> item + result + item }
assert [1,2,3].grep{ it < 3 } == [1,2]
assert [1,2,3].any{ it % 2 == 0 }
assert [1,2,3].every{ it < 4 }
assert (1..4).collect{ it * 2 }.join() == '2468'
def numbers = [ 5, 7, 9, 12 ]
assert numbers.findAll { it in 6..10 } == [7,9]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" }
def words = ['ant', 'buffalo', 'cat', 'dinosaur']
assert words.findAll{ w -> w.size() > 4 } == ['buffalo', 'dinosaur']
assert words.collect{ it[0] } == ['a', 'b', 'c', 'd']
map.each() { key, value -> println "${key} == ${value}" };
list.eachWithIndex() { obj, i -> println " ${i}: ${obj}" }; // 0: xxx
map.eachWithIndex() { obj, i -> println " ${i}: ${obj}" }; // 0: key=value
fpath = ".\\sample.txt"
file = new File(fpath)
line = 0
file.eachLine { println (++line + ": " + it) }
fpath = ".\\fold"
file = new File(fpath)
file.eachFile { println (it) }
★GroovyCollections Utility Class
def classes = ['A', 'B']
def methods = ['min', 'max', 'sum']
def combinations = GroovyCollections.combinations([classes, methods])
assert 2 * 3 == combinations.size()
assert [['A', 'min'], ['B', 'min'], ['A', 'max'], ['B', 'max'], ['A', 'sum'], ['B', 'sum']] == combinations
assert 3 == combinations.findAll { it[0] == 'A' }.size()
def keys = ['username', 'email']
def values = ['Andy', 'xxx@gmail.com', 'not-tranposed']
def transpose = GroovyCollections.transpose([keys, values, [0, 1]])
assert 2 == transpose.size()
assert [['username', 'Andy', 0], ['email', 'xxx@gmail.com', 1]] == transpose
★List
assert [].size() == 0
assert [1,2,3,4] == (1..4)
assert [1,2,3] + [1] == [1,2,3,1]
assert [1,2,3] + 1 == [1,2,3,1]
assert [1,2,3] << [1] == [1,2,3,[1]]
assert [1,2,3,1] - [1] == [2,3]
assert [1,2,3] * 2 == [1,2,3,1,2,3]
assert [1,*[2,3]] == [1,2,3]
assert [1,2,3].reverse() == [3,2,1]
assert [1,2,3].disjoint([4,5,6])
assert [1,2,3].intersect([4,3,1]) == [3,1]
assert [1,2,3].collect{ it + 3 } == [4,5,6]
assert [1,2,3,1].unique().size() == 3 //uniqueは直接に上書き
assert [1,2,3,1].count(1) == 2
assert [1,2,3,4].min() == 1
assert [1,2,3,4].max() == 4
assert [1,2,3,4].sum() == 10
assert [4,2,1,3].sort() == [1,2,3,4]
assert [4,2,1,3].findAll{ it % 2 == 0 } == [4,2]
def animals = ['cat', 'kangaroo', 'koala', 'dog']
def kanimals = animals[1..2]
assert animals.findAll{ it =~ /k.*/ } == kanimals
assert animals.find{ it =~ /k.*/ } == kanimals[0]
assert animals.grep(~/k.*/) == kanimals
assert [[1, 2, 3, 4], ['a', 'b', 'c', 'd']].transpose()
== [[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd']]
assert [[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd']].flatten()
== [1, 'a', 2, 'b', 3, 'c', 4, 'd']
def list = ['a', 'b', 'c', 'd']
list[1..1] = ['1', '2']
assert list == ['a', '1', '2', 'c', 'd']
def list = ['a', 'b', 'c', 'd', 'e']
list[1..3] = ['1', '2', '3']
assert list == ['a', '1', '2', '3', 'e']
def list = ['a', 'b', 'c']
list[1] = ['1', '2']
assert list == ['a', ['1', '2'], 'c']
def list = ['a', 'b', 'c', 'd', 'e']
list[1..3] = ['1', '2']
assert list == ['a', '1', '2', 'e']
def list = [1, 2, 3, 5, 7, 8]
assert list.groupBy{ it % 2 } == [1:[1, 3, 5, 7], 0:[2, 8]]
assert 1*1*2*3*4 == [1,2,3,4].inject(1) { x, y -> x * y }
def list = [5, 6, 7, 8]
assert list.get(2) == 7
assert list[2] == 7
assert list instanceof java.util.List
def list = 100..200
def sub = list[1, 3, 20..25, 33]
assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
assert [1, 3, 5] == ['a', 'bbb', 'ccccc']*.size()
def list = ['a','b','c','d']
def newList = []
list.collect( newList ) {
it.toUpperCase()
}
或いは
def clos = { it.toUpperCase() }
list.collect( newList, clos )
★Map
assert [:].size() == 0
def map = [a:1, b:2, c:3]
assert map instanceof java.util.HashMap
assert map.size() == 3
assert map['a'] == 1
assert map.a == 1
assert map.get('a') == 1
assert map.get('d') == null
assert map.get('d', 0) == 0 // デフォルト値を設定
assert map.d == 0 // 設定された後なので
map['e'] = 1
assert map.e == 1
def key = 'a'
assert ['x':1] == [x:1]
assert ['a':1] == [(key):1]
assert ['c':100, *:['a':11, 'aa':22, 'aaa':33]]
== ['c':100, 'a':11, 'aa':22, 'aaa':33]
★Range
assert 1..10 == new IntRange(1, 10)
assert 1..<5 == 1..4
assert -2..<2 == -2..1
assert 2..<-2 == 2..-1
assert (1..10).size() == 10
assert (1..5).step(1) == [1, 2, 3, 4, 5]
assert (1..5).step(2) == [1, 3, 5]
assert ('A'..'E').step(2) == ['A', 'C', 'E']
assert (3..1).isReverse()
assert !(1..3).isReverse()
assert (1..2).contains(1)
assert !(1..2).contains(3)
assert (1..5).containsAll([1, 2, 3, 4])
def range = 5..8
assert range.from == 5
assert range.to == 8
assert range.reverse() == 8..5
assert range.size() == 4
assert range.get(2) == 7
assert range[2] == 7
assert range instanceof java.util.List
def range = 'a'..'d'
assert range.size() == 4
assert range.get(2) == 'c'
assert range[2] == 'c'
assert range instanceof java.util.List
assert range.contains('d')
assert ! range.contains('e')
★Inject Method
def total = 0
(1..4).each { total += it }
assert 10 == total
あるいは
def total = (1..4).inject(0) { result, i -> result + i }
assert 10 == total
def list = [1,2,3]
result = list.inject(0){s, l -> s += l }
assert 6 == result
def list = ['like','sports']
result = list.inject('I'){s, l -> "$s $l" }
assert "I like sports" == result
def a = [1, 2, 3]
def b = [4, 5, 6]
def m = [a, b].transpose().inject([:]) { s, l -> s + [(l[0]): l[1]] }
assert m == [1: 4, 2: 5, 3: 6]
サンプル1
class Person {
String username
String email
}
def persons = [
new Person(username:'Andy', email: 'xxx@gmail.com'),
new Person(username:'Tom', email: 'yyy@gmail.com')
]
// An empty map as the starting point for the result
def map = persons.inject([:]) { result, person ->
result[person.username] = person.email
result
}
assert [Andy: 'xxx@gmail.com', Tom: 'yyy@gmail.com'] == map
サンプル2
Java版
abstract class A {
public int getTotal(int[] values) {
int total = 10;
for (int value : values) {
total += strategy(value);
}
return total;
}
protected abstract int strategy(int value);
}
class B extends A {
protected int strategy(int value) {
return value / 2;
}
}
class C extends A {
protected int strategy(int value) {
return value * 2;
}
}
assertEquals(new B().getTotal(new int[]{0, 1, 2}), 10 + 1/2 + 1);
assertEquals(new C().getTotal(new int[]{0, 1, 2}), 10 + 2 + 4);
Groovy版
Closure a = { values, check -> values.inject(10){x, y -> x + check(y)} }
Closure b = { a(it) {it / 2} }
Closure c = { a(it) {it * 2} }
assert b([0, 1, 2]) == 10 + 1/2 + 1
assert c([0, 1, 2]) == 10 + 2 + 4