1. Groovy安装
-
GROOVY_HOME:D:/Install/Dev/Groovy
-
PATH:%GROOVY_HOME%\bin
-
groovy -v,groovy script.groovy
-
Eclipse插件:Groovy Development Tool
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-bom</artifactId>
<version>4.0.17</version>
<scope>import</scope>
<type>pom</type>
</dependency>
2. Default Import
-
java.io.*;
-
java.lang.*;
-
java.math.BigDecimal;
-
java.math.BigInteger;
-
java.net.*;
-
java.util.*;
-
groovy.lang.*;
-
groovy.util.*;
3. Multi Method
-
groovy中,被调用的方法是在运行时选择,称为runtime dispatch
或multi-method,即将在运行时根据参数类型来选择方法; -
而在Java正好想法,方法是编译时根据声明的类型选择,
如下所示,用Java编写,用Java和Groovy编译:
int method(String arg) {
return 1;
}
int method(Object arg) {
return 2;
}
Object o = "Object";
int result = method(o);
# Java
assertEquals(2, result);
# Groovy:
assertEquals(1, result);
# 因Java将使用静态信息类型,即o被声明为Object,
# 而Groovy在运行时选择,用String调用故选择String版本;
4. Array Initializer
-
Java中,数组初始化有如下两种形式:
int[] shorthand = {1, 2, 3};
int[] longhand = new int[] {4, 5, 6};
-
而Groovy中,{……}块是闭包(closure)保留的,故不能使用shorthand方式创建;
int[] groovy = [1, 2, 3]
def groovy3Plus = new int[] {1, 2, 3}
5. Package Scope Visibility
-
groovy中,声明属性可省略修饰符,这是私有字段,有对应的getter和setter;
class Person {
String name
}
-
可使用@PackageScope来声明包字段,
class Person {
@PackageScope String name
}
6. ARM Block
-
groovy 3+ 提供java的arm twr语法,
也提供各种依赖于闭包的方法,相同效果更实用;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
public class Arm{
public static void arm() {
Path file = Path.of("/path/to/file");
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();
}
}
}
new File('filePath').eachLine('UTF-8') {
println it
}
new File('filePath').eachLine('UTF-8',){reader ->
reader.eachLine {
println it
}
}
7. Inner Class
-
匿名内部类和嵌套内部类类似于Java,但从这些类中访问局部变量不一定是final,
在生成内部类字节码时,借鉴groovy.lang.Closure的实现细节; -
静态内部类最受支持:
class A {
static class B {}
}
new A.B()
-
匿名(Anonymous)内部类:
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)
8. Lambda Method Reference
Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);
Runnable run = { println 'run' }
list.each { println it }
list.each(this.println())
9. GString
-
双引号字符串被解释为GString值,若使用Groovy和
Java编译器编译具有含$字符的Str类,Groovy可能编译失败; -
虽通常若Api声明参数类型,Groovy将在GString和String间自动转换,
但注意接受Object参数,然后检查实际类型的Java Api;
10. String and Character
-
Groovy中单引号用于String,双引号用于String或GString,
取决于字符串中是否有插值(interpolation);
assert 'c'.class == String
assert "c".class == String
assert "c${1}".class in GString
-
只有当赋值给char类型变量时,groovy才会自动将单字符String强制转换为char,
当使用char类型参数调用方法时,需显示强制转换,或确保值已提前强制转换;
char a = 'a'
assert Character.digit(a, 16) == 10: 'But Groovy does boxing'
assert Character.digit((char) 'a', 16) == 10
try {
assert Character.digit('a', 16) == 10
assert false: 'Need explicit cast'
} catch(MissingMethodException e) {
}
-
groovy支持单char和多char强制转换,两者存在细微差异,
Groovy样式强制转换更宽松(lenient),
并采用第一个字符,而C-style强制类型转换则会失败;
// for single char strings, both are the same
assert ((char) "c").class == Character
assert ("c" as char).class == Character
// for multi char strings they are not
try {
((char) 'cx') == 'c'
assert false: 'will fail - not castable'
} catch(GroovyCastException e) {
}
assert ('cx' as char) == 'c'
assert 'cx'.asType(char) == 'c'
11. Behaviour of
-
Java中==表示对象的基本类型(primitive)或标识(identity)相等,
groovy中==表示所有地方相等(equality); -
对非基本数据类型,当计算可比较对象的相等性时(evaluating equality),
它转换为a.compareTo(b) == 0,否则转换为a.equals(b); -
要检查标识(引用相等)(identity (reference equality)),
请使用is():a.is(b),或使用全等式,a === b,c !== d;
12. Primitive and Wrapper
-
Java中支持基本数据类型和包装类自动装箱和拆箱,
public class Main {
float f1 = 1.0f;
Float f2 = 2.0f;
float add(Float a1, float a2) { return a1 + a2; }
Float calc() { return add(f1, f2); }
public static void main(String[] args) {
Float calcResult = new Main().calc();
System.out.println(calcResult);
}
}
class Main {
float f1 = 1.0f
Float f2 = 2.0f
float add(Float a1, float a2) { a1 + a2 }
Float calc() { add(f1, f2) }
}
assert new Main().calc() == 3.0
-
groovy也支持基本数据类型和对象类型,单在推动OO纯粹性(purity)方面更进一步,
视一切皆对象,任何基本数据类型变量或属性都可像对象一样处理,并将按需自动包装, -
虽基本数据类型可能被覆盖(under the cover),但只要可能,
基本类型的使用与正常对象无法区分(indistinguishable),按需装箱或拆箱;
public class Main {
public float z1 = 0.0f;
public static void main(String[] args){
# 编译失败
new Main().z1.equals(1.0f);
}
}
class Main {
float z1 = 0.0f
}
assert !(new Main().z1.equals(1.0f))
int i
m(i)
void m(long l) {
println "in m(long)"
}
void m(Integer i) {
println "in m(Integer)"
}
|
# Primitive Type
jshell> float f1 = 0.0f
f1 ==> 0.0
jshell> float f2 = -0.0f
f2 ==> -0.0
jshell> f1 == f2
$3 ==> true
# Wrapper Class
jshell> Float f1 = 0.0f
f1 ==> 0.0
jshell> Float f2 = -0.0f
f2 ==> -0.0
jshell> f1.equals(f2)
$3 ==> false
float f1 = 0.0f
float f2 = -0.0f
Float f3 = 0.0f
Float f4 = -0.0f
assert f1 == f2
assert (Float) f1 != (Float) f2
assert f3 != f4
assert (float) f3 == (float) f4
assert !f1.equals(f2)
assert !f3.equals(f4)
assert f1.equalsIgnoreZeroSign(f2)
assert f3.equalsIgnoreZeroSign(f4)