bingmous

欢迎交流,不吝赐教~

导航

Groovy Document 4.0.14

官方文档:https://groovy-lang.org/documentation.html

下载安装

https://groovy.apache.org/download.html#distro ,下载binary,apache-groovy-binary-4.0.21.zip,解压,

配置GROOVY_HOME,配置GROOVY_HOME/binpath,配置JAVA_HOME

将bin目录配置到path,groovy -v验证

jdk要求:jdk8-jdk16

与Java的区别

默认的imports

以下包会自动导入

java.io.*

java.lang.*

java.math.BigDecimal

java.math.BigInteger

java.net.*

java.util.*

groovy.lang.*

groovy.util.*

多方法 或者叫运行时分发

在Groovy中,方法调用基于参数的类型在运行时才确定。而java,与之相反,方法调用基于参数声明的类型,在编译时就确定了。

int method(String arg) {
    return 1;
}
int method(Object arg) {
    return 2;
}
Object o = "Object";
int result = method(o); //in java 2, in groovy 1

这是因为java使用了类型的静态信息,其中oObject类型,Groovy在运行时根据参数的实际类型进行调用。

数组初始化

在java里,有两种初始化数组的方法:

int[] array = {1, 2, 3};             // Java array initializer shorthand syntax
int[] array2 = new int[] {4, 5, 6};  // Java array initializer long syntax

在Groovy中,{...}保留给闭包使用的,所以不能使用上面第一种进行初始化,可以使用字面列表标记:

int[] array = [1, 2, 3]

在Groovy3+,支持了java长语法初始化

def array2 = new int[] {1, 2, 3} // Groovy 3.0+ supports the Java-style array initialization long syntax

包可见性

在Groovy中,忽略字段的修饰符并不会导致这个字段为包私有,而是为private,并且会生成对应的getter/setter方法

class Person {
    String name
}

如果要创建包私有的字段,使用注解:

class Person {
    @PackageScope String name
}

自动资源管理

java7增加了自动资源管理(try-with-resource)

Path file = Paths.get("/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();
}

Groovy3+支持了这样的写法,但是Groovy提供了其他各种各样更方便的闭包写法,可以达到统一的效果。

new File('/path/to/file').eachLine('UTF-8') {
   println it
}

//或者 这种写法跟java更接近
new File('/path/to/file').withReader('UTF-8') { reader ->
   reader.eachLine {
       println it
   }
}

内部类

匿名内部类和嵌套类与java相近,但是也有一些不同,比如在这样的类中访问局部变量不要求是final的,生成内部类字节码时,一些实现细节在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)

创建非静态内部类实例
java里面:

public class Y {
    public class X {}
    public X foo() {
        return new X();
    }
    public static X createX(Y y) {
        return y.new X();
    }
}

在Groovy3之前不支持,必须使用new X(y)。注意:Groovy支持调用有一个参数的方法但是不传递参数,这个参数值为null。调用构造器也是,那么,调用new X()时调用了new X(this)可能有问题,可能也是一个正常的调用,官方还没有好的方式防止你这样做

lambda表达式和方法引用操作符

java8+支持lambda表达式和方法引用操作符:

Runnable run = () -> System.out.println("Run");  // Java
list.forEach(System.out::println);

Groovy3+也支持,之前必须使用闭包:

Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)

GStrings

双引号引用的字面量作为GString类型,有时带有$符号的String类型会产生编译错误。一般情况下Groovy会自动转换GString和String

String和字符字面量

在Groovy中,单引号引用的是String,使用双引号引用的是String或者GString,取决于里面是否有插值:

assert 'c'.class == String
assert "c".class == String
assert "c${1}".class in GString

当赋值单引号引用的内容给char类型时,会自动类型转换,但是调用方法时必须显式转换

char a = 'a' //自动类型转换String为char
assert Character.digit(a, 16) == 10: 'But Groovy does boxing'
assert Character.digit((char) 'a', 16) == 10 //强制类型转为char c-style

try {
  assert Character.digit('a', 16) == 10 //必须显式转换
  assert false: 'Need explicit cast'
} catch(MissingMethodException e) {
}

多个字符会使用第一个字符,C类型的转换则会失败

// for single char strings, both are the same
assert ((char) "c").class == Character //c-style强制类型转换
assert ("c" as char).class == Character //groovy类型转换

// for multi char strings they are not
try {
  ((char) 'cx') == 'c' //c-style类型转换会失败 无法转换
  assert false: 'will fail - not castable'
} catch(GroovyCastException e) {
}
assert ('cx' as char) == 'c' //groovy类型转换更宽容 使用第一个字符
assert 'cx'.asType(char) == 'c'  //groovy类型转换更宽容 使用第一个字符

==的行为

java里面==指原生类型相等或者对象引用相等,在Groovy中,==在所有的地方都有意义,对于非原生类型,会转换为a.compareTo(b),如果是Comparable对象,会使用a.equals(b)

如果要判断引用是否相等,使用a.is(b),在Groovy3+,可以使用a === b或者c !== d

原生类型与包装类型

java支持原生类型的自动装箱、拆箱,Groovy也支持,同时Groovy将所有的原生类型都在需要的时候进行自动装箱。

class Main {
    float z1 = 0.0f
}
assert !(new Main().z1.equals(1.0f)) // groovy可以编译 java无法编译

java扩展类型的宽度优于类型装箱

int i
m(i)

void m(long l) { // java会调用这个方法
    println "in m(long)"
}

void m(Integer i) { //groovy则调用这个方法
    println "in m(Integer)"
}

使用@CompileStatic原生数据类型优化

因为groovy在大多数地方都把原生类型转换为包装类型,会产生低效率的字节码,可以使用@CompileStatic,则使用原生类型表达式,会产生和java一样的字节码

正负零的边界情况

java里原生类型的正负零是相等的,但是包装类equals是不相等的。在groovy里,因为会自动转换,为了避免混淆,推荐遵循下面的做法:

  • 如果期望区分正零和负零,使用equals,或者在使用==前将原生类型转换为包装类型
  • 如果想忽略区别,直接使用equalsIgnoreZeroSign,或者在使用==之前,将包装类型转为原生类型

约定

java可以自动扩展或者窄化数据类型,groovy进行了扩展:https://groovy-lang.org/differences.html#_conversions

其他的关键字

as

def

in

trait

it // within closures

Groovy没有java那么严格,可以在一些不允许出现关键字的地方使用,比如var var = [def: 1, as: 2, in: 3, trait: 4],但是不建议使用。

Groovy关键字:https://docs.groovy-lang.org/latest/html/documentation/core-syntax.html#_keywords

posted on 2024-04-22 21:13  Bingmous  阅读(34)  评论(0编辑  收藏  举报