1. Overview
1.概述
Groovy is a dynamic, scripting language for the JVM. It compiles to bytecode and blends seamlessly with Java code and libraries.
Groovy是一种用于JVM的动态脚本语言。它可以编译成字节码,并与Java代码和库无缝融合。
In this article, we’re going to take a look some of the essential features of Groovy, including basic syntax, control structures, and collections.
在这篇文章中,我们将看看Groovy的一些基本功能,包括基本语法、控制结构和集合。
Then we will look at some of the main features that make it an attractive language, including null safety, implicit truth, operators, and strings.
然后我们将看看使其成为一种有吸引力的语言的一些主要特征,包括空值安全、隐式真值、运算符和字符串。
2. Environment
2.环境
If we want to use Groovy in Maven projects, we need to add the following to the pom.xml:
如果我们想在Maven项目中使用Groovy,我们需要在pom.xml中添加以下内容:</em
<build>
<plugins>
// ...
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.5</version>
</plugin>
</plugins>
</build>
<dependencies>
// ...
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.10</version>
</dependency>
</dependencies>
The most recent Maven plugin can be found here and the latest version of the groovy-all here.
最新的Maven插件可以在这里找到,最新版本的groovy-all这里。
3. Basic Features
3.基本特征
There are many useful features in Groovy. Now, let’s look at the basic building blocks of the language and how it differs from Java.
Groovy中有许多有用的功能。现在,让我们看看该语言的基本构件,以及它与Java的不同之处。
Now, let’s look at the basic building blocks of the language and how it differs from Java.
现在,让我们来看看该语言的基本构件,以及它与Java的区别。
3.1. Dynamic Typing
3.1.动态类型化
One of the most important features of Groovy is its support for dynamic typing.
Groovy最重要的功能之一是它对动态类型的支持。
Type definitions are optional and actual types are determined at runtime. Let’s take a look at these two classes:
类型定义是可选的,实际类型在运行时确定。让我们来看看这两个类。
class Duck {
String getName() {
'Duck'
}
}
class Cat {
String getName() {
'Cat'
}
}
Those two classes define the same getName method, but it is not defined explicitly in a contract.
这两个类定义了相同的getName方法,但它没有在契约中明确定义。
Now, imagine that we have a list of objects containing ducks and cats that have the getName method. With Groovy, we can do the following:
现在,想象一下,我们有一个包含鸭子和猫的对象列表,这些对象有getName方法。通过Groovy,我们可以做以下事情。
Duck duck = new Duck()
Cat cat = new Cat()
def list = [duck, cat]
list.each { obj ->
println obj.getName()
}
The code will compile, and the output of the code above would be:
该代码将被编译,上面代码的输出将是。
Duck
Cat
3.2. Implicit Truthy Conversion
3.2.隐性真理的转换。
Like in JavaScript, Groovy evaluates every object to a boolean if required, e.g. when using it inside an if statement or when negating the value:
像JavaScript一样,Groovy在需要时将每个对象评估为布尔值,例如在if语句中使用它,或者在否定值时。
if("hello") {...}
if(15) {...}
if(someObject) {...}
There are a few simple rules to remember about this conversion:
关于这种转换,有几个简单的规则需要记住。
- Non-empty Collections, arrays, maps evaluate to true
- Matcher with at least one match evaluates to true
- Iterators and Enumerations with further elements are coerced to true
- Non-empty Strings, GStrings and CharSequences, are coerced to true
- Non-zero numbers are evaluated to true
- Non-null object references are coerced to true
If we want to customize the implicit truthy conversion, we can define our asBoolean() method.
如果我们想自定义隐含的truthy转换,我们可以定义我们的asBoolean()方法。
3.3. Imports
3.3.进口
Some packages get imported by default, and we don’t need to import them explicitly:
有些包是默认导入的,我们不需要明确导入它们。
import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
4. AST Transforms
4.AST的转变
AST (Abstract Syntax Tree) transforms allows us to hook into the Groovy compilation process and customize it to meet our needs. This is done at compilation time, so there is no performance penalty when running application. We can create our AST transformations, but we can also use the built-in ones.
AST(抽象语法树)转换使我们能够钩住Groovy的编译过程,并定制它以满足我们的需求。这是在编译时完成的,所以在运行应用程序时不会有性能损失。我们可以创建我们的AST转换,但我们也可以使用内置的AST。
We can create our transformations, or we can benefit from the built-in ones.
我们可以创造我们的转变,或者我们可以从内置的转变中受益。
Let’s take a look at some annotations worth knowing.
让我们来看看一些值得了解的注释。
4.1. Annotation TypeChecked
4.1.注释TypeChecked
This annotation is used for forcing the compiler to do strict type checking for annotated pieces of code. The type checking mechanism is extensible, so we can even provide even stricter type checking than available in Java when desired.
这个注解用于强迫编译器对注解的代码片段进行严格的类型检查。类型检查机制是可扩展的,因此我们甚至可以在需要时提供比Java中更严格的类型检查。
Let’s take a look at the example below:
让我们看一下下面的例子。
class Universe {
@TypeChecked
int answer() { "forty two" }
}
If we try to compile this code, we’ll observe the following error:
如果我们试图编译这段代码,我们会观察到以下错误。
[Static type checking] - Cannot return value of type java.lang.String on method returning type int
The @TypeChecked annotation can be applied to classes and methods.
@TypeChecked注解可以应用于类和方法。
4.2. Annotation CompileStatic
4.2.注释CompileStatic
This annotation allows the compiler to execute compile-time checks as it is done with Java code. After that, the compiler performs a static compilation, thus bypassing the Groovy metaobject protocol.
这个注解允许编译器执行编译时检查,就像对Java代码那样。之后,编译器会执行静态编译,从而绕过Groovy元对象协议。
When a class is annotated, all methods, properties, files, inner classes, etc. of the annotated class will be type-checked. When a method is annotated, static compilation is applied only to those items (closures and anonymous inner classes) that are enclosed by that method.
当一个类被注解时,被注解的类的所有方法、属性、文件、内类等都将被类型检查。当一个方法被注解时,静态编译只适用于那些被该方法所包围的项目(闭包和匿名的内部类)。
5. Properties
5.属性
In Groovy, we can create POGOs (Plain Old Groovy Objects) that work the same way as POJOs in Java, although they’re more compact because getters and setters are automatically generated for public properties during compilation. It’s important to remember that they will be generated only if they’re not already defined.
在Groovy中,我们可以创建POGO(Plain Old Groovy Objects),其工作方式与Java中的POJO相同,不过它们更加紧凑,因为在编译过程中会为公共属性自动生成getters和setters。重要的是要记住,只有当它们还没有被定义时才会被生成。
This gives us the flexibility of defining attributes as open fields while retaining the ability to override the behavior when setting or getting the values.
这给了我们将属性定义为开放字段的灵活性,同时保留了设置或获取值时覆盖行为的能力。
Consider this object:
考虑到这个对象。
class Person {
String name
String lastName
}
Since the default scope for classes, fields, and methods is public – this is a public class, and the two fields are public.
由于类、字段和方法的默认范围是public – 这是一个公共类,两个字段是公共的。
The compiler will convert these into private fields and add getName(), setName(), getLastName() and setLasfName() methods. If we define the setter and getter for a particular field, the compiler will not create a public method.
编译器将把这些转换为私有字段,并添加getName()、setName()、getLastName()和setLasfName()方法。如果我们为一个特定的字段定义了setter和getter,编译器将不会创建一个公共方法。
5.1. Shortcut Notations
5.1.捷径符号
Groovy offers a shortcut notation for getting and setting properties. Instead of the Java-way of calling getters and setters, we can use a field-like access notation:
Groovy为获取和设置属性提供了一个快捷的符号。我们可以使用一个类似于字段的访问符号,而不是像Java那样调用getters和setters的方式。
resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME
resourcePrototype.setName("something")
resourcePrototype.name = "something"
6. Operators
6.操作者
Let’s now take a look at new operators added on top of those known from plain Java.
现在让我们来看看在普通Java的基础上增加的新操作符。
6.1. Null-Safe Dereference
6.1.空值安全的析取
The most popular one is the null-safe dereference operator “?” which allows us to avoid a NullPointerException when calling a method or accessing a property of a null object. It’s especially useful in chained calls where a null value could occur at some point in the chain.
最受欢迎的是null-safe解除引用操作符 “?”,它允许我们在调用一个方法或访问一个null对象的属性时避免NullPointerException。这在链式调用中特别有用,因为在链式调用的某个点上可能会出现null值。
For example, we can safely call:
例如,我们可以安全地调用。
String name = person?.organization?.parent?.name
In the example above if a person, person.organization, or organization.parent are null, then null is returned.
在上面的例子中,如果person、person.organization或organization.parent是null,那么会返回null。
6.2. Elvis Operator
6.2.猫王操作员
The Elvis operator “?:” lets us condense ternary expressions. These two are equivalent:
猫王操作符 “?:“让我们浓缩三元表达式。这两个是等价的。
String name = person.name ?: defaultName
and
和
String name = person.name ? person.name : defaultName
They both assign the value of person.name to the name variable if it is Groovy true (in this case, not null and has a non-zero length).
如果person.name是Groovy true(在这种情况下,不是null,并且具有non-zero的长度),它们都将person.name的值分配给name变量。
6.3. Spaceship Operator
6.3.宇宙飞船操作员
The spaceship operator “<=>” is a relational operator that performs like Java’s compareTo() which compares two objects and returns -1, 0, or +1 depending on the values of both arguments.
飞船操作符“<=>”是一个关系操作符,其性能类似于Java的compareTo(),它对两个对象进行比较并根据两个参数的值返回-1、0或+1。
If the left argument is greater than the right, the operator returns 1. If the left argument is less than the right, the operator returns −1. If the arguments are equal, 0 is returned.
如果左边的参数大于右边的参数,运算符返回1。如果左边的参数小于右边的参数,操作者返回-1。如果参数相等,则返回0。
The greatest advantage of using the comparison operators is the smooth handling of nulls such that x <=> y will never throw a NullPointerException:
使用比较运算符的最大优势是顺利处理nulls,这样x <=> y就不会抛出NullPointerException。
println 5 <=> null
The above example will print 1 as a result.
上面的例子将打印1作为结果。
7. Strings
7.弦乐
There are multiple ways for expressing string literals. The approach used in Java (double-quoted strings) is supported, but it is also allowed to use single quotes when preferred.
有多种方法来表达字符串字面。支持Java中使用的方法(双引号字符串),但也允许在首选时使用单引号。
Multi-line strings, sometimes called heredocs in other languages, are also supported, using triple quotes (either single or double).
多行字符串,有时在其他语言中称为heredocs,也被支持,使用三重引号(单引号或双引号)。
Multi-line strings, sometimes called heredocs in other languages, are also supported, using triple quotes (either single or double).
多行字符串,有时在其他语言中称为heredocs,也被支持,使用三重引号(单引号或双引号)。
Strings defined with double quotes support interpolation using the ${} syntax:
用双引号定义的字符串支持使用 ${}语法进行插值。
def name = "Bill Gates"
def greeting = "Hello, ${name}"
In fact, any expression can be placed inside the ${}:
事实上,任何表达式都可以放在${}里面。
def name = "Bill Gates"
def greeting = "Hello, ${name.toUpperCase()}"
A String with double quotes is called a GString if it contains an expression ${}, otherwise, it is a plain String object.
如果一个带双引号的字符串包含一个表达式${},它就被称为GString,否则,它就是一个普通的Stringobject。
The code below will run without failing the test:
下面的代码在运行时不会出现测试失败。
def a = "hello"
assert a.class.name == 'java.lang.String'
def b = 'hello'
assert b.class.name == 'java.lang.String'
def c = "${b}"
assert c.class.name == 'org.codehaus.groovy.runtime.GStringImpl'
8. Collections and Maps
8.收藏和地图
Let’s take a look at how some basic data structures are handled.
让我们来看看一些基本的数据结构是如何处理的。
8.1. Lists
8.1.列表
Here’s some code to add a few elements to a new instance of ArrayList in Java:
下面是一些代码,在Java中为一个新的ArrayList实例添加一些元素。
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
And here’s the same operation in Groovy:
下面是Groovy中的相同操作。
List list = ['Hello', 'World']
Lists are by default of type java.util.ArrayList and can also be declared explicitly by calling the corresponding constructor.
列表的默认类型是java.util.ArrayList,也可以通过调用相应的构造函数显式声明。
There isn’t a separate syntax for a Set, but we can use type coercion for that. Either use:
对于Set没有单独的语法,但是我们可以使用类型coercion来实现。要么使用。
Set greeting = ['Hello', 'World']
or:
或。
def greeting = ['Hello', 'World'] as Set
8.2. Map
8.2.地图
The syntax for a Map is similar, albeit a bit more verbose, because we need to be able to specify keys and values delimited with colons:
Map的语法与此类似,但要更啰嗦一些,因为我们需要能够指定用冒号分隔的键和值。
def key = 'Key3'
def aMap = [
'Key1': 'Value 1',
Key2: 'Value 2',
(key): 'Another value'
]
After this initialization, we will get a new LinkedHashMap with the entries: Key1 -> Value1, Key2 -> Value 2, Key3 -> Another Value.
在这个初始化之后,我们将得到一个新的LinkedHashMap,其中有一些条目。Key1 -> Value1, Key2 -> Value 2, Key3 -> Another Value。
We can access entries in the map in many ways:
我们可以通过多种方式访问地图中的条目。
println aMap['Key1']
println aMap[key]
println aMap.Key1
9. Control Structures
9.控制结构
9.1. Conditionals: if-else
9.1.条件语句 if-else
Groovy supports the conditional if/else syntax as expected:
Groovy支持条件性的if/else语法,正如预期的那样。
if (...) {
// ...
} else if (...) {
// ...
} else {
// ...
}
9.2. Conditionals: switch-case
9.2.条件语 换位思考
The switch statement is backward compatible with Java code so that we can fall through cases sharing the same code for multiple matches.
switch语句是向后兼容Java代码的,这样我们就可以通过共享相同代码的案例来落下多个匹配。
The most important difference is that a switch can perform matching against multiple different value types:
最重要的区别是,一个switch可以对多种不同的值类型进行匹配。
def x = 1.23
def result = ""
switch ( x ) {
case "foo":
result = "found foo"
break
case "bar":
result += "bar"
break
case [4, 5, 6, 'inList']:
result = "list"
break
case 12..30:
result = "range"
break
case Number:
result = "number"
break
case ~/fo*/:
result = "foo regex"
break
case { it < 0 }: // or { x < 0 }
result = "negative"
break
default:
result = "default"
}
println(result)
The example above will print number.
上面的例子将打印number.。
9.3. Loops: while
9.3.循环 while
Groovy supports the usual while loops like Java does:
Groovy像Java一样支持常见的while循环。
def x = 0
def y = 5
while ( y-- > 0 ) {
x++
}
9.4. Loops: for
9.4.循环 for
Groovy embraces this simplicity and strongly encourages for loops following this structure:
Groovy拥护这种简单性,并强烈鼓励for循环遵循这种结构。
for (variable in iterable) { body }
The for loop iterates over iterable. Frequently used iterables are ranges, collections, maps, arrays, iterators, and enumerations. In fact, any object can be an iterable.
for循环对iterable进行迭代。经常使用的可迭代对象是范围、集合、地图、数组、迭代器和枚举。事实上,任何对象都可以是一个可迭代的对象。
Braces around the body are optional if it consists of only one statement. Below are examples of iterating over a range, list, array, map, and strings:
如果主体只由一条语句组成,则其周围的括号是可选的。下面是迭代range、list、array、map和strings的例子。
def x = 0
for ( i in 0..9 ) {
x += i
}
x = 0
for ( i in [0, 1, 2, 3, 4] ) {
x += i
}
def array = (0..4).toArray()
x = 0
for ( i in array ) {
x += i
}
def map = ['abc':1, 'def':2, 'xyz':3]
x = 0
for ( e in map ) {
x += e.value
}
x = 0
for ( v in map.values() ) {
x += v
}
def text = "abc"
def list = []
for (c in text) {
list.add(c)
}
Object iteration makes the Groovy for-loop a sophisticated control structure. It’s a valid counterpart to using methods that iterate over an object with closures, such as using Collection’s each method.
对象迭代使Groovy for- 循环成为一个复杂的控制结构。这是一个有效的对应方法,使用闭合的对象进行迭代,例如使用Collection的each方法。
The main difference is that the body of a for loop isn’t a closure, this means this body is a block:
主要的区别是,for 循环的主体不是一个闭包,这意味着这个主体是一个块。
for (x in 0..9) { println x }
whereas this body is a closure:
而这个机构是一个封闭的。
(0..9).each { println it }
Even though they look similar, they’re very different in construction.
尽管它们看起来很相似,但在结构上非常不同。
A closure is an object of its own and has different features. It can be constructed in a different place and passed to the each method. However, the body of the for-loop is directly generated as bytecode at its point of appearance. No special scoping rules apply.
闭包是它自己的一个对象,具有不同的特征。它可以在不同的地方构造并传递给each方法。然而,for-循环的主体在其出现的地方直接生成bytecode。没有特殊的范围规则适用。
10. Exception Handling
10.异常处理
The big difference is that checked exceptions handling is not enforced.
最大的区别是,检查过的异常处理是不强制的。
To handle general exceptions, we can place the potentially exception-causing code in a try/catch block:
为了处理一般的异常,我们可以将可能引起异常的代码放在try/catch块中。
try {
someActionThatWillThrowAnException()
} catch (e)
// log the error message, and/or handle in some way
}
By not declaring the type of exception we catch, any exception will be caught here.
由于没有声明我们捕获的异常类型,任何异常都会在这里被捕获。
11. Closures
11.关闭
Simply put, a closure is an anonymous block of executable code which can be passed to variables and has access to data in the context where it was defined.
简单地说,闭包是一个匿名的可执行代码块,它可以被传递给变量,并且可以访问它所定义的上下文中的数据。
They’re also similar to anonymous inner classes, although they don’t implement an interface or extend a base class. They are similar to lambdas in Java.
它们也类似于匿名内类,尽管它们没有实现一个接口或扩展一个基类。它们类似于Java中的lambdas。
Interestingly, Groovy can take full advantage of the JDK additions that have been introduced to support lambdas, especially the streaming API. We can always use closures where lambda expressions are expected.
有趣的是,Groovy可以充分利用JDK为支持lambdas而增加的功能,特别是流式API。我们总是可以在期待lambda表达式的地方使用闭包。
Let’s consider the example below:
让我们考虑下面的例子。
def helloWorld = {
println "Hello World"
}
The variable helloWorld now holds a reference to the closure, and we can execute it by calling its call method:
变量helloWorld现在持有对闭包的引用,我们可以通过调用其call方法来执行它。
helloWorld.call()
Groovy lets us use a more natural method call syntax – it invokes the call method for us:
Groovy让我们使用更自然的方法调用语法–它为我们调用了call method。
helloWorld()
11.1. Parameters
11.1.参数[/strong]
Like methods, closures can have parameters. There are three variants.
像方法一样,闭包可以有参数。有三种变体。
In the latter example, because there’s nothing declpersistence_startared, there is only one parameter with the default name it. The modified closure that prints what it is sent would be:
在后一个例子中,因为没有什么declpersistence_startared,所以只有一个默认名为it的参数。打印它所发送的内容的修改后的闭包将是。
def printTheParam = { println it }
We could call it like this:
我们可以这样称呼它。
printTheParam('hello')
printTheParam 'hello'
We can also expect parameters in closures and pass them when calling:
我们也可以在闭包中期待参数,并在调用时传递参数。
def power = { int x, int y ->
return Math.pow(x, y)
}
println power(2, 3)
The type definition of parameters is the same as variables. If we define a type, we can only use this type, but can also it and pass in anything we want:
参数的类型定义与变量是一样的。如果我们定义了一个类型,我们只能使用这个类型,但也可以它和传入任何我们想要的东西。
def say = { what ->
println what
}
say "Hello World"
11.2. Optional Return
11.2.可选择的返回
The last statement of a closure may be implicitly returned without the need to write a return statement. This can be used to reduce the boilerplate code to a minimum. Thus a closure that calculates the square of a number can be shortened as follows:
闭包的最后一条语句可以隐式返回,而不需要写一个返回语句。这可以用来将模板代码减少到最低限度。因此,一个计算数字的平方的闭包可以被缩短为如下。
def square = { it * it }
println square(4)
This closure makes usage of the implicit parameter it and the optional return statement.
这个闭包使用了隐式参数it和可选的返回语句。
12. Conclusion
12.结论
This article provided a quick introduction to the Groovy language and its key features. We started by introducing simple concepts such as basic syntax, conditional statements, and operators. We also demonstrated some more advanced features such as operators and closures.
本文快速介绍了Groovy语言及其主要特性。我们首先介绍了一些简单的概念,如基本语法、条件语句和运算符。我们还演示了一些更高级的功能,如运算符和闭包。
If you want to find more information about the language and it’s semantics, you may go directly to the official site.
如果你想找到更多关于该语言和它的语义的信息,你可以直接到官方站点。