Apache Groovy 的 4.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.XmlParser
、groovy.ant.AntBuilde
r和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
,自动生成 firstName
和 lastName
作为 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
。 小数值的前导零现在是可选的,因此现在支持 .5
和 0.5
。
Groovy 4 有一些重大更改,例如删除了 Antlr2 解析器,并且不再可能生成基于调用点的字节码。 一些模块,如 groovy-jaxb 和 groovy-bsf 已被删除。 groovy-all pom 现在包含 groovy-yaml 模块,而 groovy-testng 模块已被删除。
发行说明 中提供了重大更改和新功能的完整列表。