当前位置: 首页 > 工具软件 > Apache Groovy > 使用案例 >

Groovy4的新特性概览

贺运良
2023-12-01

Apache Groovy4.0.0 版本引入了switch表达式、密封类、内置类型检查器、内置宏方法、记录类、JavaShell、POJO注解、Groovy 合同、Groovy 集成查询和 TOML 支持。 此版本还包含一些较小的改进和重大更改。

鼓励开发人员在升级到 Groovy 4.0.0 时更改其依赖项,因为 Maven groupId 已从 org.codehaus.groovy 更改为 org.apache.groovy .

Java 平台模块系统 (JPMS) 不允许在多个模块中使用相同的类和包名。 Groovy 3 仍然提供了类的重复版本,简而言之,是时候停止使用groovy.util.XmlSlurper和开始使用了groovy.xml.XmlSlurper。同样,您现在应该使用groovy.xml.XmlParsergroovy.ant.AntBuilder和groovy.test.GroovyTestCase前面提到的 Groovy 3 发行说明中提到的其他类。

Switch 表达式 现在支持补充现有的 switch 语句:

def result = switch(i) {
    case 0 -> 'January'
    case 1 -> 'February'
    //...
    default -> throw new IllegalStateException('Invalid number of month')
}

一个代码块可以用于多个语句:

case 0 -> { def month = 'January'; def year = Year.now().getValue(); 
    month + " " + year }

switch 的实现与 Java 不同,因为并非所有可能的值都需要 case 分支。 当没有提供默认分支时,Groovy 会隐式添加默认分支,返回 null

可以使用 sealed 关键字或 @Sealed 注解创建密封类。 同时编译时会自动检测允许的子类。 permits 子句可以与 sealed 关键字一起使用,permittedSubclasses 属性可以与 @Sealed 注解一起使用以显式 定义允许的子类:

@Sealed(permittedSubclasses = [Dog, Cat]) interface Animal {}
@Singleton final class Dog implements Animal {
    String toString() { 'Dog' }
}
@Singleton final class Cat implements Animal {
    String toString() { 'Cat' }
}
sealed interface Animal permits Dog, Cat {}
@Singleton final class Dog implements Animal {
    String toString() { 'Dog' }
}
@Singleton final class Cat implements Animal {
    String toString() { 'Cat' }
}

记录类是新的功能之一,与现有的 @Immutable Groovy 功能相当:

record Student(String firstName, String lastName) { }

结果类是隐式 final,自动生成 firstNamelastName 作为 private final 字段,firstName()lastName() 方法,带有两个参数的默认构造函数,0L 的 **serialVersionUID**和 toString() equals()hashcode() 方法。

Groovy 提供了内置的类型检查器来削弱类型检查或加强类型检查。 此版本引入了 groovy-typecheckers 模块,其中包含多个类型检查器。 @TypeChecked 注解可以在项目添加依赖后使用,以便在编译期间验证正则表达式是否有效。 以下表达式缺少通常会导致运行时错误的右括号:

@TypeChecked(extensions = 'groovy.typecheckers.RegexChecker')
def year() {
    def year = '2022'
    def matcher = year =~ /(\d{4}/
}

但是,类型检查器在编译期间显示错误:

Groovyc: [Static type checking] - Bad regex: Unclosed group near index 6
(\d{4}

与类型检查器类似,一些宏方法现在可以通过 groovy-macro-library 模块使用,例如 SV 宏,它从变量名称和值创建一个字符串:

def studentName = "James"
def age = 42
def courses = ["Introduction to Java" , "Java Concurrency", "Data structures"]

println SV(studentName, age, courses)
studentName=James, age=42, courses=[Introduction to Java, Java Concurrency, 
    Data structures]

NV 宏创建了一个 NamedValue,它允许进一步处理名称和值:

def namedValue = NV(age)
assert namedValue instanceof NamedValue
assert namedValue.name == 'age' && namedValue.val == 42

JavaShell 功能使开发人员能够运行 Java 代码片段:

import org.apache.groovy.util.JavaShell

def student = 'record Student(String firstName, String lastName) {}'
Class studentClass = new JavaShell().compile('Student', student)
assert studentClass.newInstance("James", "Gosling")
    .toString() == 'Student[firstName=James, lastName=Gosling]'

POJO 注解是另一个新功能,它允许将 Groovy 用作与 Lombok 相当的预处理器。 @POJO 注解表明该类更像是 POJO 而不是高级 Groovy 对象,需要处理 @CompileStatic 注解。

groovy-contracts 模块允许指定类不变量,以及类和接口的前置和后置条件:

import groovy.contracts.*

@Invariant({ coursesCompleted >= 0 })
class Student {
    int coursesCompleted = 0
    boolean started = false

    @Requires({ started })
    @Ensures({ old.coursesCompleted < coursesCompleted })
    def processCourses(newCoursesCompleted) { 
        coursesCompleted += newCoursesCompleted 
    }
}

只要不满足前提条件,就会显示错误消息,例如 started 前提条件应该是 true

def student = new Student()
student.processCourses(2)
org.apache.groovy.contracts.PreconditionViolation: <groovy.contracts.Requires> 
    Student.java.lang.Object processCourses(java.lang.Object) 

started
|
false

当不满足后置条件时,例如处理的课程数量下降时,会显示另一条错误消息:

def student = new Student()
student.setStarted(true)
student.processCourses(-2)
org.apache.groovy.contracts.PostconditionViolation: <groovy.contracts.Ensures> 
    Student.java.lang.Object processCourses(java.lang.Object) 

old.coursesCompleted < coursesCompleted
|   |                | |
|   0                | -2
|                    false

Groovy-Integrated Query(GINQ 或 GQuery)功能允许查询集合,例如list、map、自定义域对象或其他结构化数据,很多像 SQL:

from student in students
orderby student.age
where student.age > 20
select student.firstName, student.lastName, student.age
from student in students
leftjoin university in universities on student.university == university.name
select student.firstName, student.lastName, university.city

groovy-toml 提供了对基于 TOML 的文件的支持:

def tomlBuilder = new TomlBuilder()
tomlBuilder.records {
    student {
        firstName 'James'
        // ...
    }
}

def tomlSlurper = new TomlSlurper()
def toml = tomlSlurper.parseText(tomlBuilder.toString())

assert 'James' == toml.records.student.firstName

引入了各种较小的改进,例如缓存 GString toString 值以提高性能。 范围可以指定为包含 1..10 或在右侧排除 1..<10; 现在也可以在左边排除 1<..10 或两者兼有 1<..<10。 小数值的前导零现在是可选的,因此现在支持 .50.5

Groovy 4 有一些重大更改,例如删除了 Antlr2 解析器,并且不再可能生成基于调用点的字节码。 一些模块,如 groovy-jaxbgroovy-bsf 已被删除。 groovy-all pom 现在包含 groovy-yaml 模块,而 groovy-testng 模块已被删除。

发行说明 中提供了重大更改和新功能的完整列表。

 类似资料: