Apache Groovy は、 Java プラットフォーム向けのJava構文と互換性のあるオブジェクト指向プログラミング言語です。静的言語と動的言語の両方の機能を持ち、 Python、Ruby、Smalltalkと同様の機能を備えています。Java プラットフォームのプログラミング言語およびスクリプト言語として使用でき、 Java 仮想マシン(JVM)バイトコードにコンパイルされ、他の Java コードやライブラリとシームレスに相互運用できます。Groovy は、 Java と同様の波括弧構文を使用します。Groovy は、クロージャ、複数行文字列、および文字列に埋め込まれた式をサポートしています。Groovy の強力な機能の多くは、アノテーションによってトリガーされる抽象構文木(AST) 変換にあります。
Groovy 1.0 は 2007 年 1 月 2 日にリリースされ、Groovy 2.0 は 2012 年 7 月にリリースされました。バージョン 2 以降、Groovy は静的にコンパイルできるようになり、Java に近い型推論とパフォーマンスが提供されています。 [ 3 ] [ 4 ] Groovy 2.4 は、2015 年 3 月に終了したPivotal Softwareのスポンサーシップの下での最後のメジャー リリースでした。 [ 5 ]その後、Groovy はガバナンス構造をApache Software Foundationのプロジェクト管理委員会に変更しました。[ 6 ]
ジェームズ・ストラチャンは、 2003 年 8 月に自身のブログで Groovy の開発について初めて言及しました。[ 7 ] 2004 年 3 月に Groovy は JSR 241 [ 8 ]としてJava Community Process (JCP)に提出され、投票により承認されました。2004 年から 2006 年にかけていくつかのバージョンがリリースされました。JCP の標準化作業が開始されると、バージョン番号が変更され、2007 年 1 月 2 日に「1.0」と呼ばれるバージョンがリリースされました。さまざまなベータ版とリリース候補版が 1.1 と番号付けされた後、2007 年 12 月 7 日に Groovy 1.1 Final がリリースされ、多くの変更を反映してすぐに Groovy 1.5 に番号が変更されました。
2007年、GroovyはJAX 2007イノベーション賞で1位を獲得しました。[ 9 ] 2008年には、GroovyウェブフレームワークであるGrailsがJAX 2008イノベーション賞で2位を獲得しました。[ 10 ]
2008年11月、SpringSourceはGroovyとGrailsの会社(G2One)を買収した。[ 11 ] 2009年8月、VMwareがSpringSourceを買収した。[ 12 ]
2012年4月、8年間の活動休止の後、仕様責任者はJSR 241のステータスを休止に変更した。[ 8 ]
Strachanは2007年のGroovy 1.0リリースの1年前に静かにプロジェクトを離れた。2016年10月、Strachanは「私は今でもGroovy(Jenkinsパイプラインは最高だ!)、Java、Go、TypeScript、Kotlinが大好きです」と述べた。[ 13 ]
2012年7月2日、Groovy 2.0がリリースされ、他の新機能の中でも特に静的コンパイルと静的型チェックが追加されました。
2013 年 4 月にEMC Corporation (EMC) と VMwareがPivotal Software の合弁会社をスピンオフしたとき、Groovy と Grails はその製品ポートフォリオの一部となりました。Pivotal は 2015 年 4 月をもって Groovy と Grails のスポンサーを終了しました。 [ 5 ] 同じ月に Groovy は、そのガバナンス構造を Codehaus リポジトリからApache Software Foundationのインキュベーターを経由したプロジェクト管理委員会 (PMC) に変更しました。[ 6 ] Groovy は 2015 年 11 月に Apache のインキュベーターを卒業し、トップレベルのプロジェクトになりました。[ 14 ]
2020年2月7日にGroovy 3.0がリリースされました。[ 15 ]バージョン4.0は2022年1月25日にリリースされました。[ 16 ]
ほとんどの有効なJavaファイルは、有効なGroovyファイルでもあります。2つの言語は似ていますが、GroovyコードはJavaが必要とするすべての要素を必要としないため、よりコンパクトになります。[ 17 ]これにより、Javaプログラマーは、慣れ親しんだJava構文から始めて、より多くのGroovyプログラミングの慣用表現を習得することで、Groovyを段階的に学ぶことができます。[ 18 ]
Groovy には Java にはない機能として、静的型付けと動的型付け (キーワードを使用def)、演算子オーバーロード、リストと連想配列(マップ) のネイティブ構文、正規表現のネイティブサポート、ポリモーフィック反復、文字列補間、追加されたヘルパーメソッド、およびnull ポインタを自動的にチェックする安全なナビゲーション演算子 (たとえば、、または) などがあります。[ 19 ]?.variable?.method()variable?.field
バージョン 2 以降、Groovy はモジュール性 (jarプロジェクトで使用するものだけを出荷することで Groovy ライブラリのサイズを削減)、型チェック、静的コンパイル、Project Coin 構文の強化、マルチキャッチ ブロック、およびJava 7invokedynamicで導入された命令を使用した継続的なパフォーマンス強化もサポートしています。[ 20 ]
Groovyは、インラインのドキュメントオブジェクトモデル(DOM)構文を使用することで、 XMLやHTMLなどのマークアップ言語をネイティブにサポートしています。この機能により、多様なデータ資産を統一された簡潔な構文とプログラミング手法で定義および操作することが可能になります。
Javaとは異なり、Groovyソースコードファイルは、クラス定義外のコードが含まれている場合、mainメソッドを持つクラスである場合、またはRunnableやGroovyTestCaseである場合は、(コンパイルされていない)スクリプトとして実行できます。Groovyスクリプトは、実行前に完全に解析、コンパイル、生成されます(PythonやRubyと同様)。これは内部で行われ、コンパイルされたバージョンはプロセスの成果物として保存されません。[ 21 ]
GroovyBeansはGroovy版のJavaBeansです。Groovyはgetterとsetterを暗黙的に生成します。以下のコードでは、setColor(String color)とgetColor()が暗黙的に生成されます。colorに直接アクセスしているように見える最後の2行は、実際には暗黙的に生成されたメソッドを呼び出しています。[ 22 ]
class AGroovyBean { String color }def myGroovyBean = new AGroovyBean ()myGroovyBean.setColor ( ' baby blue' ) assert myGroovyBean.getColor ( ) == ' baby blue'myGroovyBean.color = ' pewter ' assert myGroovyBean.color == ' pewter 'Groovyは、Javaの配列構文を彷彿とさせる、リストとマップを扱うためのシンプルで一貫性のある構文を提供します。[ 23 ]
def movieList = [ 'Dersu Uzala' , 'Ran' , 'Seven Samurai' ] // 配列のように見えるが、リストであるassert movieList [ 2 ] == 'Seven Samurai' movieList [ 3 ] = 'Casablanca' // リストに要素を追加するassert movieList . size () == 4def monthMap = [ 'January' : 31 , 'February' : 28 , 'March' : 31 ] // マップを宣言assert monthMap [ 'March' ] == 31 // エントリにアクセスmonthMap [ 'April' ] = 30 // マップにエントリを追加assert monthMap . size () == 4Groovy は、、拡張モジュール (Groovy 2 のみ)、Objective-C のようなカテゴリ、およびを介してプロトタイプ拡張をサポートしています。[ 24 ]ExpandoMetaClassDelegatingMetaClass
ExpandoMetaClassRubyのオープンクラスの概念と同様に、クラス内の変更を簡単に表現できるドメイン固有言語(DSL)を提供します。
Number.metaClass { sqrt = { Math.sqrt ( delegate ) } }アサート9 。sqrt () == 3 4をアサートします。sqrt () == 2Groovyにおけるプロトタイプ作成によるコード変更は、Javaからは見えません。これは、Groovyの各属性/メソッド呼び出しがメタクラスレジストリを経由するためです。変更されたコードは、Javaからメタクラスレジストリにアクセスすることによってのみ確認できます。
Groovyでは、メソッドのオーバーライドも可能でgetProperty()、propertyMissing()開発者はオブジェクトへの呼び出しをインターセプトし、簡略化されたアスペクト指向の方法でそれらのアクションを指定できます。次のコードにより、クラスはプロパティjava.lang.Stringに応答できるようになりますhex。
enum Color { BLACK ( '#000000' ), WHITE ( '#FFFFFF' ), RED ( '#FF0000' ), BLUE ( '#0000FF' ) String hex Color ( String hex ) { this . hex = hex } }String.metaClass.getProperty = { String property - > def stringColor = delegate if ( property == ' hex ' ) { Color.values ( ) . find { it.name ( ) . equalsIgnoreCase stringColor } ?. hex } }assert "WHITE" . hex == "#FFFFFF" assert "BLUE" . hex == "#0000FF" assert "BLACK" . hex == "#000000" assert "GREEN" . hex == nullGrailsフレームワークはメタプログラミングを多用して、GORMの動的ファインダー(User.findByName('Josh')など)を可能にしている。[ 25 ]
Groovyの構文では、状況によっては括弧とドットを省略できます。以下のGroovyコード
(コーヒー)に(砂糖、牛乳)と(お酒)を加える次のように書くことができます
コーヒーに砂糖、ミルク、お酒を入れて飲むこれにより、平易な英語のようなドメイン固有言語(DSL)の開発が可能になります。
Groovyは主にオブジェクト指向言語ですが、関数型プログラミングの機能も備えています。
Groovy のドキュメントによると、「Groovy のクロージャは「メソッド ポインタ」に似ており、コードを後日記述して実行することを可能にします」。[ 26 ] Groovy のクロージャは、自由変数、つまり明示的にパラメータとして渡されていないが宣言コンテキストに存在する変数、部分適用(Groovy では「カリー化」[ 27 ]と呼んでいます)、委譲、暗黙的、型付き、型なしのパラメータをサポートしています。
特定の型のコレクションを操作する場合、コレクションに対する操作に渡されるクロージャは推論できます。
リスト= [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]/* * ゼロ以外の数値は真に強制されるため、it % 2 == 0 (偶数) の場合は偽になります。* 暗黙の "it" パラメーターの型は、IDE によって Integer として推論されます。* 次のように記述することもできます。* list.findAll { Integer i -> i % 2 } * list.findAll { i -> i % 2 } */ def odds = list . findAll { it % 2 }assert odds == [ 1 , 3 , 5 , 7 , 9 ]クロージャブロック内には、実装を参照することなく一連の式を記述でき、後から委譲を用いて応答オブジェクトを割り当てることができます。
// このコードブロックには、実装を参照しない式が含まれていますdef operations = { declare 5 sum 4 divide 3 print }/* * このクラスは、上記のクロージャで使用できる操作を処理します。 * 同じメソッドを持つ別のクラスを宣言することもできますが、計算にはたとえば Web サービス操作を使用することもできます。 */ class Expression { BigDecimal value/* * パラメータとして整数が渡されますが、 定義どおり BigDecimal 型に変換されます。 * クラスに 'declare(Integer value)' メソッドがあれば、そちらが使用されます。 */ def declare ( BigDecimal value ) { this . value = value } def sum ( BigDecimal valueToAdd ) { this . value += valueToAdd } def divide ( BigDecimal divisor ) { this . value /= divisor } def propertyMissing ( String property ) { if ( property == "print" ) println value } }// 上記のコードブロック内の式に応答する対象がここで定義されます。operations.delegate = new Expression ( ) operations ()通常部分適用と呼ばれるこのGroovyの機能により、クロージャのパラメータを引数のいずれかのデフォルト パラメータに設定し、バインドされた値を持つ新しいクロージャを作成できます。メソッドに 1 つの引数を指定すると、引数curry()1 が固定されます。N 個の引数を指定すると、引数 1 から N までが固定されます。
def joinTwoWordsWithSymbol = { symbol , first , second -> first + symbol + second } assert joinTwoWordsWithSymbol ( '#' , 'Hello' , 'World' ) == 'Hello#World'def concatWords = joinTwoWordsWithSymbol.curry ( ' ' ) assert concatWords ( ' Hello' , 'World' ) == 'Hello World'def prependHello = concatWords.curry ( 'Hello' ) // def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello') assert prependHello ( ' World' ) == 'Hello World'カリーは逆方向(最後のN個の引数を固定する)にも使用できますrcurry()。
def power = { BigDecimal value , BigDecimal power -> value ** power }def square = power.rcurry ( 2 ) def cube = power.rcurry ( 3 )assert power ( 2 , 2 ) == 4 assert square ( 4 ) == 16 assert cube ( 3 ) == 27Groovyは、遅延評価[ 28 ] [ 29 ] 、reduce/fold [ 30 ] 、無限構造と不変性[ 31 ]などをサポートしています。 [ 32 ]
JavaScript Object Notation ( JSON ) および XML の処理において、Groovy はビルダーパターンを採用しており、データ構造の生成を簡潔にしています。例えば、次の XML のようにです。
<languages> <language year= "1995" > <name> Java </name> <paradigm> object oriented </paradigm> <typing> static </typing> </language> <language year= "1995" > <name> Ruby </name> <paradigm> functional, object oriented </paradigm> <typing> duck typing, dynamic </typing> </language> <language year= "2003" > <name> Groovy </name> <paradigm> functional, object oriented </paradigm> <typing> duck typing, dynamic, static </typing> </language> </languages>以下のGroovyコードを使用して生成できます。
def writer = new StringWriter () def builder = new groovy.xml.MarkupBuilder ( writer ) builder.languages { language ( year : 1995 ) { name "Java" paradigm " object oriented" typing "static" } language(year: 1995 ) { name " Ruby " paradigm " functional , object oriented " typing " duck typing, dynamic" } language ( year : 2003 ) { name "Groovy" paradigm "functional, object oriented" typing "duck typing, dynamic, static" } }また、ストリーミング方式で処理することもできますStreamingMarkupBuilder。実装を JSON に変更するには、MarkupBuilderを に置き換えることができますJsonBuilder。[ 33 ]
これを解析して関数型言語を検索するには、GroovyのfindAllメソッドが役立ちます。
def languages = new XmlSlurper ( ). parseText writer.toString ( )// ここでは、Groovy の正規表現構文を使用して、ブール値に強制変換されるマッチャー (=~) を使用します。// 値に文字列が含まれている場合は true、そうでない場合は false になります。def functional = languages . language . findAll { it . paradigm =~ "functional" } assert functional . collect { it . name } == [ "Groovy" , "Ruby" ]Groovyでは、GStringsを使用することで、文字列を変数や式で補間することができます。[ 34 ]
BigDecimal account = 10.0 def text = "アカウントの現在の残高は $account です" assert text == "アカウントの現在の残高は 10.0 です"変数や式を含むGStringは、二重引用符を使用して宣言する必要があります。
複雑な式は波括弧で囲む必要があります。これにより、式の一部が周囲の文字列の一部として解釈されるのを防ぎ、式自体の一部として解釈されるようにします。
BigDecimal minus = 4.0 text = "口座の現在の残高は${account - minus}です" assert text == "口座の現在の残高は6.0です"// 式を分離するための括弧がない場合、次のようになります: text = "アカウントの現在の残高は $account - minus" assert text == "アカウントの現在の残高は 10.0 - minus"矢印構文を用いることで、式の評価を遅延させることができます。
BigDecimal tax = 0.15 text = "口座の現在の残高は${->account - account*tax}です" tax = 0.10// 税額は GString の宣言後に変更されました。式// 変数は、式が実際に評価される必要がある場合にのみバインドされます: assert text == "口座の現在の残高は 9.000 です"Groovy の公式ドキュメントによると、「Groovy コンパイラが Groovy スクリプトとクラスをコンパイルすると、処理のどこかの時点で、ソース コードは最終的にメモリ上で具象構文木として表現され、その後抽象構文木に変換されます。AST 変換の目的は、開発者がコンパイル プロセスにフックして、JVM によって実行されるバイト コードに変換される前に AST を変更できるようにすることです。AST 変換により、Groovy はコンパイル時のメタ プログラミング機能が向上し、実行時のパフォーマンスを低下させることなく、言語レベルで強力な柔軟性を実現できます。」[ 35 ]
GroovyにおけるASTの例は以下のとおりです。
その他にもいくつかあります。
テストフレームワークであるSpockは、 AST変換を使用して、プログラマがGroovyでサポートされていない構文でテストを記述できるようにしますが、関連するコードはAST内で有効なコードに操作されます。[ 36 ]このようなテストの例は次のとおりです。
def "#a と #b の最大値は #c です" () { expect: Math . max ( a , b ) == cここで、a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 }Groovyのドキュメントによると、「トレイトは、動作の構成、インターフェースの実行時実装、動作のオーバーライド、静的型チェック/コンパイルとの互換性を可能にする言語の構造的構成要素です。」
トレイトは、デフォルトの実装と状態の両方を保持するインターフェースと見なすことができます。トレイトは、traitキーワードを使用して定義されます。
trait FlyingAbility { /* トレイトの宣言 */ String fly () { "I'm flying!" } /* トレイト内のメソッドの宣言 */ }その後、キーワードを使用して通常のインターフェースのように使用できますimplements。
class Bird implements FlyingAbility {} /* Bird クラスの機能に FlyingAbility 特性を追加します */ def bird = new Bird () /* 新しい Bird をインスタンス化します */ assert bird . fly () == "I'm flying!" /* Bird クラスは FlyingAbility 特性の動作を自動的に取得します */特性によって、単純な構成からテストまで、幅広い能力が可能になります。
Groovyの採用例としては、以下のようなものが挙げられます。
多くの統合開発環境(IDE)やテキストエディタはGroovyをサポートしています。
Groovyには別の実装方法が1つあります。