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 ==> falsefloat 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)