前言
由於專案需要用到 Groovy 語言,這兩天對其進行了粗略的學習,本文是對學習做的一個簡單總結,主要內容參考於官方文件(Groovy 的官方文件還是非常不錯的,強烈推薦閱讀),希望本文對準備學習使用或者對 Groovy 感興趣的同學有所幫助,如有不對之處還望指出哈,對這門語言的理解還是比較膚淺的。
簡介
Groovy 是 Apache 旗下的一門基於 JVM 平臺的動態/敏捷程式語言,在語言的設計上它吸納了 Python、Ruby 和 Smalltalk 語言的優秀特性,語法非常簡練和優美,開發效率也非常高(程式語言的開發效率和效能是相互矛盾的,越高階的程式語言效能越差,因為意味著更多底層的封裝,不過開發效率會更高,需結合使用場景做取捨)。並且,Groovy 可以與 Java 語言無縫對接,在寫 Groovy 的時候如果忘記了語法可以直接按Java的語法繼續寫,也可以在 Java 中呼叫 Groovy 指令碼,都可以很好的工作,這有效的降低了 Java 開發者學習 Groovy 的成本。Groovy 也並不會替代 Java,而是相輔相成、互補的關係,具體使用哪門語言這取決於要解決的問題和使用的場景。
快速開始
- 下載Groovy開發工具包(GDK)
www.groovy-lang.org/download.ht… - 建立Groovy專案
使用IDEA的話需要安裝Groovy的支援外掛,安裝完成後在新建專案中便會出現Groovy專案選項,選擇Groovy專案並關聯Groovy libray即可,當然也可以直接建立.groovy
檔案用命令列直接執行。 - Hello World
在Java中要輸出“hello world”需要像下面這樣,建立一個類,然後建立一個main方法。
在Groovy中,這些都可以省略,下面這4種方式都可以輸出“hello world”。public class Hello { public static void main(String[] args) { System.out.println("hello world"); } }複製程式碼
當然,也可以像Java一樣執行在類的main方法中。System.out.println("hello world"); System.out.println "hello world"; println("hello world") println 'hello world'複製程式碼
如果 Groovy 指令碼檔案裡只有執行程式碼,沒有類的定義,則 Groovy 編譯器會生成一個 Script 的子類,類名和指令碼檔案的檔名一樣,而指令碼中的程式碼會被包含在一個名為class Hello { static void main(args) { println 'hello world' } }複製程式碼
run
的方法中,同時還會生成一個main方法,作為整個指令碼的入口。所以,作為 JVM 平臺語言,與 Java 本質上還是一樣的。
與Java的一些區別
預設匯入
Groovy 會預設匯入下面這些包、類,不需要使用import
語句顯式匯入。
java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.*複製程式碼
多重方法
在 Groovy 中,呼叫的方法將在執行時被選擇。這種機制被稱為執行時分派或多重方法(multi-methods),是根據執行時實參(argument)的型別來選擇方法。Java 採用的是相反的策略:編譯時根據宣告的型別來選擇方法。
下面是一個例子,同樣的 Java 程式碼在 Java 和 Groovy 環境中執行結果是不同的.
int method(String arg) {
return 1;
}
int method(Object arg) {
return 2;
}
Object o = "Object";
int result = method(o);
// In Java
assertEquals(2, result);
// In Groovy
assertEquals(1, result);複製程式碼
產生差異的原因在於,Java 使用靜態資料型別,o 被宣告為 Object 物件,而 Groovy 會在執行時實際呼叫方法時進行選擇。因為呼叫的是 String 型別的物件,所以自然呼叫 String 版本的方法。
陣列初始化語法
在 Groovy 中,{...} 語句塊是留給閉包(Closure)使用的,所以不能像 Java 中一樣使用下面這種方式初始化陣列
int[] array = { 1, 2, 3}複製程式碼
而應該是下面這樣
int[] array = [1,2,3]複製程式碼
POJO
Groovy 預設會隱式的建立getter、setter方法,並且會提供帶參的構造器,下面兩者是等價的。
// In Java
public class Person {
private String name;
Person(String name) {
this.name = name
}
public String getName() {
return name
}
public void setName(String name) {
this.name = name
}
}
// In Groovy
class Person {
String name
}
def person = new Person(name: '張三')
assert '張三' == person.name
person.name = '李四'
//person.setName('李四')
assert '李四' == person.getName()複製程式碼
包訪問許可權
在 Java 中如果沒有顯式的指定訪問修飾符(public、protected、private
)那麼預設是包訪問許可權,但在 Groovy 中預設是public
的,所以需要使用@PackageScope
註解。
class Person {
@PackageScope String name
}複製程式碼
ARM 語句塊
ARM(Automatic Resource Management,自動資源管理)語句塊(或者叫TWR語法)從 Java 7 開始引入,用於降低IO操作程式碼的複雜度,但 Groovy 並不支援。相反,Groovy 提供多種基於閉包的方法,不但可以達到同樣的效果並且會更加簡潔優美。
//In Groovy
Path file = Paths.get("/User/lihengming/test.txt");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
//In Groovy
new File('/User/lihengming/test.txt').eachLine('UTF-8') {
println it
}
//或者這樣,更接近於Java的方式
new File('/User/lihengming/test.txt').withReader('UTF-8') { reader ->
reader.eachLine {
println it
}
}
//如果只是為了讀取並列印出文字的內容的話,下面是最簡潔的方式
print new File('/User/lihengming/test.txt').text複製程式碼
內部類
Groovy 同樣支援內部類並且實現跟 Java 是一樣的,但不應拿 Java 語言規範來考量它,應對差異情況保持冷靜與寬容(keep shaking the head about things that are different)。在Groovy中內部類看起來有點類似 groovy.lang.Closure 類的實現。
//靜態內部類
class A {
static class B {}
}
new A.B()
//匿名內部類
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer()
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(10, TimeUnit.SECONDS)複製程式碼
Lambda 表示式
Java 8 支援 Lambda 表示式和方法引用
Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);複製程式碼
Java 8 的 lambda 幾乎可以認為是匿名內部類。Groovy 並沒有採用這種語法,而採用閉包來實現。
Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)複製程式碼
GString
由於雙引號所包括起來的字串字面量會被解釋為 GString 值(即 “Groovy 字串”的簡稱),所以如果當某個類中的 String 字面量含有美元字元($)時,那麼利用 Groovy 和 Java 編譯器進行編譯時,Groovy 很可能就會編譯失敗,或者產生與 Java 編譯所不同的結果。
通常,如果某個 API 宣告瞭形參的型別,Groovy 會自動轉換 GString 和 String。要小心那些形參為 Object 的 Java API,需要檢查它們的實際型別。
字串和字元字面量
在 Groovy 中,由單引號所建立的字面量屬於 String 型別物件,而雙引號建立的字面量則可能是 String 或 GString 物件,具體分類由字面量中是否有插值來決定。
assert 'c'.getClass()==String
assert "c".getClass()==String
assert "c${1}".getClass() in GString複製程式碼
基礎語法
- Groovy 語句無需使用分號(
;
)結尾,當然加上也不會報錯,畢竟完全相容 Java 的語法。 - Groovy 中
==
等價於 Java 中的equals
方法。
註釋
註釋和 Java 一樣,支援單行(//
)、多行(/* */
)和文件註釋(/** */
)
除此之外還支援 Shebang line(UNIX系統支援一種特殊的單行註釋叫作 Shebang line,用於指明指令碼的執行環境,便於在終端中可以直接執行)#號必須是檔案的第一個字元。
#!/usr/bin/env groovy
println "Hello from the shebang line"複製程式碼
變數
Groovy 中定義變數預設訪問修飾符是public
,變數定義時遵循 Java 變數命名規範,變數名以字母、下劃線或美元符號$開始,可以包含字母、數字、下劃線和美元符號$,但關鍵字除外。除了這些規則之外,Groovy 定義變數時如果是一行定義一個型別,末尾的分號可以省略,但是如果多個變數佔一行,變數之間必須以分號分割。
Groovy 定義變數的方式和 Java 是類似的,區別在於 Groovy 提供了def
關鍵字供使用,它可以省略變數型別的定義,根據變數的值進行型別推導。
def a = 123
def b = 'b'
def c = true
boolean d = false
int e = 123複製程式碼
如果定義變數的字面量值為數字時,型別會根據數字的大小自動調整
def a = 1
assert a instanceof Integer
// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer
// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long
// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long
// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger複製程式碼
對於浮點型字面量為了精度 Groovy 預設使用的型別為 BigDecimal
def decimal = 123.456
println decimal.getClass() // class java.math.BigDecimal複製程式碼
Groovy為 數字型別提供一種更簡單的宣告型別的方式:型別字尾
- Integer 使用I或i
- Long 使用L或l
- BigInteger 使用G或g
- BigDecimal 使用G或g
- Double 使用D或d
- Float 使用F或f複製程式碼
使用例子
def a = 123I
assert a instanceof Integer
def b= 123L
assert b instanceof Long複製程式碼
字串
在Groovy種有兩種字串型別,普通字串(java.lang.String
)和插值字串(groovy.lang.GString
)。
普通字串使用單引號
println 'hello'複製程式碼
插值字串使用雙引號
def name = '張三'
println "hello $name"複製程式碼
除此之外,還支援三單引號的寫法,可以保留文字的換行及縮排格式
def strippedFirstNewline = '''line one
line two
line three
'''
println strippedFirstNewline
// 可以寫成下面這種形式,可讀性更好
def strippedFirstNewline2 = '''\
line one
line two
line three
'''
println strippedFirstNewline2複製程式碼
字元
在 Groovy 中並沒有明確的字元字面量表示形式,需要顯示的指定,有三種方式
char c1 = 'A' // 宣告型別
assert c1 instanceof Character
def c2 = 'B' as char // 用as關鍵字
assert c2 instanceof Character
def c3 = (char) 'C' // 強制型別轉換
assert c3 instanceof Character複製程式碼
方法(函式)
Groovy 方法的預設訪問修飾符是public
,方法的返回型別可以不需要宣告,但需新增def
關鍵字。有返回值的方法return
可以被省略,預設返回最後一行程式碼的執行結果,如果使用了return
關鍵字則返回指定的返回值。
String method1() {
return 'hello'
}
assert method1() == 'hello';
def method2() {
return 'hello'
}
assert method2() == 'hello';
def method3() {
'hello'
}
assert method3() == 'hello';複製程式碼
Groovy 方法的引數型別可以被省略,預設為Object型別。
def add(int a, int b) {
return a + b
}
//與上面的等價
def add(a, b) {
a + b
}複製程式碼
Groovy 方法的其他特性與Java一樣,比如支援過載、不定長引數(...)等。
閉包
Groovy 提供了閉包的支援,語法和 Lambda 表示式有些類似,簡單來說就是一段可執行的程式碼塊或函式指標。閉包在 Groovy 中是groovy.lang.Closure
類的例項,這使得閉包可以賦值給變數,或者作為引數傳遞。Groovy 定義閉包的語法很簡單,就像下面這樣。
//閉包的引數為可選項
def closure = { [closureParameters -> ] statements }複製程式碼
閉包可以訪問外部變數,而方法(函式)則不能。
def str = 'hello'
def closure={
println str
}
closure()//hello複製程式碼
閉包呼叫的方式有兩種,閉包.call(引數)或者閉包(引數),在呼叫的時候可以省略圓括號。
def closure = {
param -> println param
}
closure('hello')
closure.call('hello')
closure 'hello'複製程式碼
閉包的引數是可選的,如果沒有引數的話可以省略->
操作符。
def closure = {println 'hello'}
closure()複製程式碼
多個引數以逗號分隔,引數型別和方法一樣可以顯式宣告也可省略。
def closure = { String x, int y ->
println "hey ${x} the value is ${y}"
}複製程式碼
如果只有一個引數的話,也可省略引數的定義,Groovy提供了一個隱式的引數it
來替代它。
def closure = { it -> println it }
//和上面是等價的
def closure = { println it }
closure('hello')複製程式碼
閉包可以作為引數傳入,閉包作為方法的唯一引數或最後一個引數時可省略括號。
def eachLine(lines, closure) {
for (String line : lines) {
closure(line)
}
}
eachLine('a'..'z',{ println it })
//可省略括號,與上面等價
eachLine('a'..'z') { println it }複製程式碼
Lists
Groovy 定義 List 的方式非常簡潔,使用中括號([]
),以逗號(,
)分隔元素即可。Groovy中的 List 其實就是java.util.List
,實現類預設使用的是java.util.ArrayList
。
def numbers = [1, 2, 3]
assert numbers instanceof List
assert numbers.class == java.util.ArrayList
assert numbers.size() == 3複製程式碼
Arrays
Groovy 定義陣列的語法和 List 非常類似,區別在於陣列的定義必須指定型別為陣列型別,可以直接定義型別或者使用def定義然後通過as關鍵字來指定其型別。
String[] arrStr = ['Ananas', 'Banana', 'Kiwi'] //直接宣告型別為陣列型別 String[]
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
def numArr = [1, 2, 3] as int[] //痛過as關鍵字指定型別為陣列型別 int[]
assert numArr instanceof int[]
assert numArr.size() == 3複製程式碼
Maps
Groovy 定義 Map 的方式非常簡潔,通過中括號包含key、val的形式,key和value以冒號分隔([key:value]
)。Groovy中的Map其實就是java.util.Map
,實現類預設使用的是java.util.LinkedHashMap
。
// key雖然沒有加引號,不過Groovy會預設將其轉換為字串
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000' // 使用中括號訪問
assert colors.green == '#00FF00' // 使用點表示式訪問
colors['pink'] = '#FF00FF' // 使用中括號新增元素,相當於Java Map 的 put(key,value)方法
colors.yellow = '#FFFF00'// 使用點表示式新增元素
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap // 預設使用LinkedHashMap型別
// Groovy Map的key預設語法不支援變數,這裡的key時間上是字串'keyVal'而不是keyVal變數的值'name'
def keyVal = 'name'
def persons = [keyVal: 'Guillaume']
assert !persons.containsKey('name')
assert persons.containsKey('keyVal')
//要使用變數作為key,需要使用括號
def keyVal = 'name'
def persons = [(keyVal): 'Guillaume']
assert persons.containsKey('name')
assert !persons.containsKey('keyVal')複製程式碼
Range
在 Groovy 中可以使用..
操作符來定義一個區間物件,簡化範圍操作的程式碼。
def range = 0..5
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]
assert (0..<5).collect() == [0, 1, 2, 3, 4] // 相當於左閉右開區間
assert (0..5) instanceof List // Range實際上是List介面的實現
assert (0..5).size() == 6
assert ('a'..'d').collect() == ['a','b','c','d']//也可以是字元型別
//常見使用場景
for (x in 1..10) {
println x
}
('a'..'z').each {
println it
}
def age = 25;
switch (age) {
case 0..17:
println '未成年'
break
case 18..30:
println '青年'
break
case 31..50:
println '中年'
break
default:
println '老年'
}複製程式碼
常見使用場景
Grails
Grails 是一個基於 Groovy 語言,構建於 Spring/Spring Boot、Hibernate 之上的高生產力、一站式 Web 開發框架。特別適合小型團隊進行敏捷開發,效率非常高。由於效能和學習成本的原因,普及率比較低,大分部公司還是更傾向於選擇 Spring Boot 作為開發框架。
Gradle
Gradle 是一個基於 Apache Ant 和 Apache Maven 概念的專案自動化構建工具。它使用一種基於 Groovy 的特定領域語言(DSL)來進行構建配置,拋棄了基於XML的各種繁瑣配置,主要以面向Java應用為主,支援從 Maven 倉庫下載依賴。現在越來越多的專案(Android專案居多)使用Gradle 來作為專案的構建工具,相信未來 Gradle 也會逐漸代替 Maven,就像 Maven 代替 Ant 那樣。
使用Maven構建專案
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vs</groupId>
<artifactId>com.vs.maven.gradle</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa
</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>複製程式碼
使用Gradle構建專案
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.6.RELEASE")
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web") {
exclude module: "spring-boot-starter-tomcat"
}
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
testCompile("mysql:mysql-connector-java:5.1.25")
}複製程式碼
Spring 支援
從 Spring 2.0 版本開始對動態指令碼語言進行了支援(Spring 官方文件該部分地址),其中便包括 Groovy ,Spring 提供了<lang:groovy/>
標籤來定義 Groovy Bean 。Groovy Bean 可以通過script-source
屬性載入指令碼檔案,指令碼原始檔可以來自本地或者網路,並且可以通過refresh-check-delay
屬性監聽指令碼內程式碼變更重新裝載 Bean 實現動態 Bean 。
// from the file '/java/Calculator.java'
public interface Calculator {
int add(int x, int y);
}
// from the file '/resources/CalculatorGroovyImpl.groovy'
class CalculatorGroovyImpl implements Calculator {
int add(int x, int y) {
x + y
}
}複製程式碼
<-- from the file 'beans.xml' 省略 xmlns -->
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<lang:groovy id="calculator" script-source="classpath:CalculatorGroovyImpl.groovy" refresh-check-delay="1000"/>
</beans>複製程式碼
public class Tester {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Calculator calculator = (Calculator)context.getBean("calculator");
//嘗試修改CalculatorGroovyImpl.groovy,將 x + y,修改為x * y。
while (true){
System.out.println(calculator.add(1, 1));
TimeUnit.SECONDS.sleep(1);
}
}
}複製程式碼
從 Spring 4.0 版本開始 Spring 支援使用 Groovy DSL 來定義 Bean 的配置,詳見 Spring 官方文件該部分 。
beans {
//beanName(type)
dataSource(BasicDataSource) {
//注入屬性
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
//注入屬性,引用其他Bean
dataSource = dataSource
}
myService(MyService) {
//使用閉包定義巢狀的Bean
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}複製程式碼
ApplicationContext context = new GenericGroovyApplicationContext("beans.groovy");
MyService myService = context.getBean(MyService.class);複製程式碼
與Java整合
Groovy非常容易整合在Java環境中,利用其動態性來做規則引擎、流程引擎、動態指令碼環境,非常適合那些不不需要經常釋出但又經常變更的場景下使用。在Java中整合(呼叫)Groovy 程式碼有下面幾種方式。
Eval
groovy.util.Eval
類是最簡單的用來在執行時動態執行 Groovy 程式碼的類,提供了幾個靜態工廠方法供使用,內部其實就是對GroovyShell的封裝。
//執行Groovy程式碼
Eval.me("println 'hello world'");
//繫結自定義引數
Object result = Eval.me("age", 22, "if(age < 18){'未成年'}else{'成年'}");
assertEquals(result, "成年");
//繫結一個名為 x 的引數的簡單計算
assertEquals(Eval.x(4, "2*x"), 8);
//帶有兩個名為 x 與 y 的繫結引數的簡單計算
assertEquals(Eval.xy(4, 5, "x*y"), 20);
//帶有三個繫結引數(x、y 和 z)的簡單計算
assertEquals(Eval.xyz(4, 5, 6, "x*y+z"), 26);複製程式碼
GroovyShell
groovy.lang.GroovyShell
除了可以執行 Groovy 程式碼外,提供了更豐富的功能,比如可以繫結更多的變數,從檔案系統、網路載入程式碼等。
GroovyShell shell = new GroovyShell();
//可以繫結更多變數
shell.setVariable("age",22);
//直接求值
shell.evaluate("if(age < 18){'未成年'}else{'成年'}");
//解析為指令碼,延遲執行或者快取起來
Script script = shell.parse("if(age < 18){'未成年'}else{'成年'}");
assertEquals(script.run(), "成年");
//可以從更多位置載入/執行指令碼
//shell.evaluate(new File("script.groovy"));
//shell.evaluate(new URI("http://wwww.a.com/script.groovy"));複製程式碼
GroovyClassLoader
groovy.lang.GroovyClassLoader
是一個定製的類載入器,可以在執行時載入 Groovy 程式碼,生成 Class 物件。
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
String scriptText = "class Hello { void hello() { println 'hello' } }";
//將Groovy指令碼解析為Class物件
Class clazz = groovyClassLoader.parseClass(scriptText);
//Class clazz = groovyClassLoader.parseClass(new File("script.groovy"));
assertEquals(clazz.getName(),"Hello");
clazz.getMethod("hello").invoke(clazz.newInstance());複製程式碼
GroovyScriptEngine
groovy.util.GroovyScriptEngine
能夠處理任何 Groovy 程式碼的動態編譯與載入,可以從統一的位置載入指令碼,並且能夠監聽指令碼的變化,當指令碼發生變化時會重新載入。
//script/groovy/hello.groovy
println "hello $name"複製程式碼
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("script/groovy");
Binding binding = new Binding();
binding.setVariable("name", "groovy");
while (true){
scriptEngine.run("hello.groovy", binding);
TimeUnit.SECONDS.sleep(1);
}複製程式碼
//輸出
hello groovy
hello groovy
....
//將hello.groovy內程式碼修改為println "hi $name", GroovyScriptEngine會重新進行載入
hi groovy
hi groovy複製程式碼
JSR 223 javax.script API
JSR-223 是 Java 中呼叫指令碼語言的標準 API。從 Java 6 開始引入進來,主要目的是用來提供一種統一的框架,以便在 Java 中呼叫多種指令碼語言。JSR-223 支援大部分流行的指令碼語言,比如JavaScript、Scala、JRuby、Jython和Groovy等。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("groovy");
Bindings bindings = new SimpleBindings();
bindings.put("age", 22);
Object value = engine.eval("if(age < 18){'未成年'}else{'成年'}",bindings);
assertEquals(value,"成年");
//script/groovy/hello.groovy
//println "hello world"
engine.eval(new FileReader("script/groovy/hello.groovy"));
//hello world複製程式碼
由於 Groovy 自身已經提供了更豐富的整合機制,如果在 Java 應用中只是使用 Groovy 一種指令碼語言的話,使用 Groovy 提供的整合機制可能會更合適一點。
與Java整合大致就以上幾種方式,在使用前推薦閱讀:Groovy與Java整合常見的坑