上一篇 Gradle の入門知識を学びました。Gradle は Groovy に基づいており、今日は Groovy の基礎知識を学びます。Groovy は JVM 仮想マシンに基づく動的言語で、文法は Java の文法に似ています。Groovy は Java と完全に互換性があり、すべての Gradle ファイルは Groovy スクリプトファイルです。Gradle ファイルは Groovy 文法に基づいており、Groovy は Java と互換性があるため、Gradle ファイル内に Java コードを書くことができます。この基盤の上に、クロージャや DSL などの多くの新機能が追加されており、Groovy は非常に柔軟な動的スクリプト言語と言えます。Gradle に関連して、Groovy のいくつかの基礎知識を学びましょう。
- 文字列
- コレクション
- メソッド
- JavaBean
- クロージャ
文字列#
Groovy の特徴の一つとして、Groovy ではセミコロンが必須ではないことがあります。シングルクォートとダブルクォートはどちらも文字列定数を定義しますが、違いはシングルクォートは純粋な文字列定数であり、その文字列内の式を計算しません。一方、ダブルクォートで定義された文字列定数は合法的な式を使用して関連する計算を行うことができます。テストコードは以下の通りです:
task stringTest{
//defキーワードを使用して変数を定義
def str1 = "ダブルクォート"
def str2 = 'シングルクォート'
println "ダブルクォートで定義された文字列:"+str1
println "ダブルクォートで定義された文字列:"+str1.class
println "シングルクォートで定義された文字列:"+str2
//変数の動的変化
str1 = true;
println "ダブルクォートで定義された文字列:"+str1.class
//$演算子を使用
println "ダブルクォートで定義された文字列:${str1}"
//変数が一つの時は中括弧を省略可能
println "ダブルクォートで定義された文字列:$str1"
//シングルクォートで定義された文字列は式を使用して計算できない
println 'シングルクォートで定義された文字列:$str2'
}
以下は実行結果です:
PS E:\Gradle\study\Groovy> gradle stringTest
> Configure project :
ダブルクォートで定義された文字列:ダブルクォート
ダブルクォートで定義された文字列:class java.lang.String
シングルクォートで定義された文字列:シングルクォート
ダブルクォートで定義された文字列:class java.lang.Boolean
ダブルクォートで定義された文字列:true
ダブルクォートで定義された文字列:true
シングルクォートで定義された文字列:$str2
BUILD SUCCESSFUL in 1s
コレクション#
Groovy にもコレクションの概念があり、主に一般的な List と Map を見ていきます。以下では List と Map の一般的な操作について紹介します。
では、Groovy でListをどのように定義するのでしょうか。Groovy の List の定義方法は Java の配列に似ています。具体的な操作は以下のコードを参照してください:
task list{
//Listを定義
def list = [1,2,3,4,5,6];
def weekList = ['月曜日','火曜日','水曜日','木曜日','金曜日','土曜日','日曜日'];
println "listの型:"+list.class
println "weekListの型:"+weekList.class
//コレクション内の要素にアクセス
println '最初の要素:'+list[0]//最初の要素にアクセス
println '二番目の要素:'+list[1]//二番目の要素にアクセス
println '最後の要素:'+list[-1]//最後の要素にアクセス
println '倒数第二の要素:'+list[-2]//倒数第二の要素にアクセス
println '特定の範囲内の要素:'+list[2..4]//特定の範囲内の要素にアクセス
//eachを使用してコレクション内の要素を繰り返し処理
weekList.each{
//itを反復の要素変数として使用、間違えないように
println it
}
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\ListMap> gradle list
> Configure project :
listの型:class java.util.ArrayList
weekListの型:class java.util.ArrayList
最初の要素:1
二番目の要素:2
最後の要素:6
倒数第二の要素:5
特定の範囲内の要素:[3, 4, 5]
月曜日
火曜日
水曜日
木曜日
金曜日
土曜日
日曜日
BUILD SUCCESSFUL in 2s
では、Groovy でMapをどのように定義するのでしょうか。Groovy の Map はもちろんキーと値のペアです。具体的な定義と操作は以下のコードを参照してください:
task map{
//Mapを定義
def map = ['name':'Groovy', 'age':10];
println "mapの型:"+map.getClass().name;
//Map内の要素にアクセス
println map.name;
println map['name'];
//Map内の要素を繰り返し処理
map.each{
println "Key:${it.key},value:${it.value}"
}
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\ListMap> gradle map
> Configure project :
mapの型:java.util.LinkedHashMap
Groovy
Groovy
Key:name,value:Groovy
Key:age,value:10
BUILD SUCCESSFUL in 2s
Groovy のコレクションについてはこれくらいです。
メソッド#
Groovy のメソッドは Java のメソッドに似ていますが、書き方がより柔軟です。Groovy では return は必須ではなく、return を書かない場合、Groovy は最後の文をそのメソッドの戻り値として扱います。コードブロックとは、波括弧で囲まれたコードのことを指し、Groovy ではコードブロックを引数として渡すことができます。コレクションの繰り返し部分を参考にしてください。以下は参考コードです:
task method{
//メソッド呼び出し
methodA(1, 2)
methodA 1, 2
//メソッドの戻り値を取得
def a = methodA 10, 20
println 'メソッドの戻り値を取得:'+a
//コードブロックを引数として渡す
def list = [1,2,3,4,5];
list.each(
//クロージャ引数
{
// println it
}
)
//Groovyでは、メソッドの最後の引数がクロージャの場合、メソッドの外に直接置くことができます
list.each(){
// println it
}
//簡略化された方法
list.each{
println it
}
}
//メソッドの定義
def methodA(int a, int b){
println a + b
//Groovyではreturn文は必須ではなく、デフォルトで最後の文の結果を戻り値として扱います
a + b
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\Method> gradle method
> Configure project :
3
3
30
メソッドの戻り値を取得:30
1
2
3
4
5
BUILD SUCCESSFUL in 2s
JavaBean#
Groovy の JavaBean は Java のものに比べて柔軟で、javaBean. 属性の形式で JavaBean の属性値を取得および変更できます。対応する Getter、Setter メソッドを使用する必要はありません。直接コードを見てみましょう:
task javaBean{
//GroovyでJavaBeanを定義
Student student = new Student()
student.name = "Groovy"
student.age = 10
student.setName("Gradle")
println "名前は:"+student.name
//Getterメソッドを呼び出して値を取得することはできません
// println "名前は:"+student.getName
println "年齢は:${student.age}"
println "スコアは:"+student.score
}
class Student{
private String name
private int age
//定義されたGetterメソッドに対応する属性は直接呼び出すことができます
public String getScore(){
100
}
//属性のGetter、Setterメソッド
public String setName(String name){
this.name = name
}
public void getName(){
name
}
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\JavaBean> gradle javaBean
> Configure project :
名前は:Gradle
年齢は:10
スコアは:100
BUILD SUCCESSFUL in 2s
クロージャ#
クロージャは多くのスクリプト言語に共通する特徴で、JavaScript や Groovy などに見られます。クロージャは波括弧で囲まれたコードブロックです。以下では Groovy のクロージャについて学びます。主に二つの部分:クロージャとクロージャパラメータの渡し方、クロージャの委任について説明します。
クロージャとそのパラメータの渡し方#
以下では、クロージャを定義する方法と関連するパラメータの渡し方を見ていきます。直接コードを見てみましょう:
task closure{
//カスタムクロージャの実行
mEach{
println it
}
//クロージャにパラメータを渡す
mEachWithParams{m,n -> //m,n ->クロージャのパラメータと本体を区別します
println "${m} is ${n}"
}
}
//1.メソッドを定義し、パラメータclosureはクロージャを受け取ります
//2.クロージャの実行は波括弧内のコードの実行です
//3.クロージャが受け取るパラメータは、クロージャパラメータclosureのiであり、1つのパラメータの場合はデフォルトでit変数です
def mEach(closure){
for(int i in 1..5){
closure(i)
}
}
//クロージャにパラメータを渡す
def mEachWithParams(closure){
def map = ["name":"Groovy","age":10]
map.each{
closure(it.key, it.value)
}
}
上記のコードでは、クロージャを定義し、クロージャのパラメータの渡し方を示しています。クロージャに一つのパラメータがある場合、デフォルトで it になりますが、複数のパラメータがある場合は、パラメータを定義する必要があります。具体的には上記のコードを参照してください。以下は実行結果です:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
1
2
3
4
5
name is Groovy
age is 10
BUILD SUCCESSFUL in 2s
クロージャの委任#
Groovy のクロージャの強力な点は、クロージャメソッドの委任をサポートしていることです。Groovy のクロージャには三つの属性があります:thisObject、owner、delegate。クロージャ内で定義されたメソッドを呼び出すとき、これら三つの属性によってそのメソッドがどのオブジェクトによって実行されるかが決まります。デフォルトでは owner と delegate は等しいですが、delegate は変更可能です。Gradle のクロージャの多くの機能は、delegate を変更することで実現されます。以下にクロージャとメソッドを定義し、これら三つの属性の違いを印刷して示します:
//クロージャの委任
task delegate{
new Delegate().test{
//Groovyクロージャの三つの属性:thisObject、owner、delegate
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
//クロージャのデフォルトit
println "クロージャのデフォルトit:"+it.getClass()
//定義されたメソッドは、優先的にthisObjectを使用して処理されます
method()
//クロージャ内のメソッド
it.method()
}
}
def method(){
println "root内のメソッド:${this.getClass()}"
}
class Delegate{
def method(){
println "Delegate内のメソッド:${this.getClass()}"
}
//クロージャ
def test(Closure<Delegate> closure){
closure(this);
}
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
thisObject:class build_3ajca04o1rprxygcsq0ajvt7i
owner:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
delegate:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
クロージャのデフォルトit:class Delegate
root内のメソッド:class build_3ajca04o1rprxygcsq0ajvt7i
Delegate内のメソッド:class Delegate
BUILD SUCCESSFUL in 2s
クロージャ内で method () メソッドを呼び出すと、thisObject が method () メソッドを呼び出したことがわかります。owner や delegate ではなく、クロージャ内では thisObject がメソッドの実行を優先的に処理します。また、owner と delegate は一致していることがわかりますが、owner の優先度は delegate よりも高いです。したがって、クロージャ内のメソッド処理の順序は:thisObject > owner > delegate です。
Gradle では一般的に delegate を現在の it に指定します。これにより、delegate で指定されたオブジェクトを使用して it を操作できるようになります。以下にクロージャの delegate を指定し、委任の優先度を設定して、委任された具体的なオブジェクトがそのメソッドを実行するようにします。以下はテストコードです:
task student{
configStudent{
println "現在のit:${it}"
name = "Groovy"
age = 10
getInfo()
}
}
class Student{
String name
int age
def getInfo(){
println "name is ${name}, age is ${age}"
}
}
def configStudent(Closure<Student> closure){
Student student = new Student()
//委任オブジェクトを現在作成されたStudentインスタンスに設定
closure.delegate = student
//委任モードを優先的に設定します。設定しない場合、クロージャ内のメソッドの処理者はthisObjectです
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
//it変数を設定
closure(student)
}
以下は上記コードの実行結果です:
PS E:\Gradle\study\Groovy\Closure> gradle student
> Configure project :
現在のit:Student@18f6d755
name is Groovy, age is 10
BUILD SUCCESSFUL in 2s
まとめ#
Groovy を学ぶ目的は、Gradle ビルドツールの理解を深めることです。上記の五つの側面を通じて、Groovy についての初歩的な理解を得ました。今後、必要があれば Groovy の高度な使い方を再度確認します。