Groovy 快速入门
文章目录
- Groovy 语言
- 概述
- 简介
- 基本特点
- 动态类型
- 闭包
- 语法
- 类
- 环境准备
- 基本语法
- 第一个 Hello world 程序
- Groovy 的导入语句
- Groovy 的注释
- Groovy 的分号
- Groovy 的标识符
- Groovy 的关键字
- 数据类型
- 变量
- 运算符
- 循环
- 条件语句
- 方法
- 无参方法
- 有参方法
- 默认参数值
- 文件 I/O
- 读取文件
- 写入文件
- 获取文件大小
- 测试文件是否为目录
- 创建目录
- 删除文件
- 复制文件
- 获取目录所在驱动器
- 列出指定目录下的文件
- 列出指定目录下的所有文件,包括递归处理子目录文件
- 字符串
- 字符串索引
- 列表
- 常用方法
- 键值映射
- 正则表达式
- traits 特征
- 实现接口
- 属性
- 多重实现
- 特征继承
- 闭包
- 闭包中的形式参数
- 闭包和变量
- 闭包参数
- 集合和字符串中的闭包
- 键值对映射示例
- 异常
- 其它语法
- 非空则调用语法
- 精简的Bean
- 省略构造器
- 多重赋值
- 多方法接口实现
- 其它注解
- @Canonical 替代 toString
- @Delegate 实现委托
- @Immutable 不可变对象
- @Newify 注解
- @Singleton 单例模式
- 注意 Groovy 的 == 符号
Groovy 语言
概述
简介
Groovy是用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。
Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。
基本特点
- 构建在强大的Java语言之上 并 添加了从Python,Ruby和Smalltalk等语言中学到的 诸多特征,例如动态类型转换、闭包和元编程(metaprogramming)支持。
- 为Java开发者提供了 现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
- 支持DSL(Domain Specific Languages领域定义语言)和其它简洁的语法,让代码变得易于阅读和维护。
- 受检查类型异常(Checked Exception)也可以不用捕获。
- Groovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变得非常简单。
- 在开发Web,GUI,数据库或控制台程序时 通过 减少框架性代码 大大提高了开发者的效率。
- 支持单元测试和模拟(对象),可以 简化测试。
- 无缝集成 所有已经存在的 Java对象和类库。
- 直接编译成Java字节码,这样可以在任何使用Java的地方 使用Groovy。
- 支持函数式编程,不需要main函数。
- 一些新的运算符。
- 默认导入常用的包。
- 断言不支持jvm的-ea参数进行开关。
- 支持对对象进行布尔求值。
- 类不支持default作用域,且默认作用域为public。
- groovy中基本类型也是对象,可以直接调用对象的方法。
动态类型
类型对于变量,属性,方法,闭包的参数以及方法的返回类型都是可有可无的,都是在给变量赋值的时候才决定它的类型, 不同的类型会在后面用到,任何类型都可以被使用,即使是基本类型 (通过自动包装(autoboxing)). 当需要时,很多类型之间的转换都会自动发生,比如在这些类型之间的转换: 字符串(String),基本类型(如int) 和类型的包装类 (如Integer)之间,可以把不同的基本类型添加到同一数组(collections)中。
闭包
闭包就是可以使用参数的代码片段,每个闭包会被编译成继承groovy.lang.Closure类的类,这个类有一个叫call方法,通过该方法可以传递参数并调用这个闭包.它们可以访问并修改在闭包创建的范围内的变量,在闭包内创建的变量在闭包被调用的范围内同样可以被引用, 闭包可以保存在变量中并被作为参数传递到方法中。
语法
Groovy 语法与Java 语言的语法很相似,虽然 Groovy 的语法源于Smalltalk和Ruby这类语言的理念,但是可以将它想像成 Java 语言的一种更加简单、表达能力更强的变体。(在这点上,Ruby与 Groovy 不同,因为它的语法与 Java 语法差异很大。)
许多 Java 开发人员喜欢 Groovy 代码和 Java 代码的相似性。从学习的角度看,如果知道如何编写 Java 代码,那就已经了解 Groovy 了。Groovy 和 Java 语言的主要区别是:完成同样的任务所需的 Groovy 代码比 Java 代码更少。
类
Groovy类和java类一样,完全可以用标准java bean的语法定义一个Groovy类。但作为另一种语言,可以使用更Groovy的方式定义类,这样的好处是,可以少写一半以上的javabean代码。
- 不需public修饰符
如前面所言,Groovy的默认访问修饰符就是public,如果Groovy类成员需要public修饰,则根本不用写它。
- 不需要类型说明
同样前面也说过,Groovy也不关心变量和方法参数的具体类型。
- 不需要getter/setter方法
在很多ide(如eclipse)早就可以为程序员自动产生getter/setter方法了,在Groovy中,不需要getter/setter方法–所有类成员(如果是默认的public)根本不用通过getter/setter方法引用它们(当然,如果一定要通过getter/setter方法访问成员属性,Groovy也提供了它们)。
- 不需要构造函数
不再需要程序员声明任何构造函数,因为实际上只需要两个构造函数(1个不带参数的默认构造函数,1个只带一个map参数的构造函数–由于是map类型,通过这个参数可以构造对象时任意初始化它的成员变量)。
- 不需要return
Groovy中,方法不需要return来返回值。
环境准备
java 项目中使用 Groovy 引入其依赖即可
<dependency><groupId>org.apache.groovy</groupId><artifactId>groovy</artifactId><version>4.0.2</version>
</dependency>
基本语法
创建一个以 .groovy 为后缀的文件,我们可以在这文件中像开发java代码一样简单的去使用 groovy,并且 groovy 提供的语法更加简洁。
我们可以完全像开发 Java 代码一样去编写 Groovy,也可以根据 Groovy 的语法来简化编写。
第一个 Hello world 程序
class Example {static void main(String[] args) {// 使用 println 就可打印输出,并且类和方法默认就是public,可以不用写println('Hello World');}
}
运行
Hello World
Groovy 的导入语句
和 Java 一样,都是使用 Import 进行导入
import groovy.xml.MarkupBuilder // Import 进行导入需要的类
def xml = new MarkupBuilder() // def 就是动态类型,在Groovy可以不用指定具体的类型,就像js中的var一样
在编译的 Groovy 字节码文件中,Groovy 已经默认帮我们导入了一些jar包,这些 jar 包可以不用再显示的导入
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
Groovy 的注释
和 Java 一样,支持单行 //
和多行注释 /**/
// Using a simple println statement to print output to the console/* This program is the first programThis program shows how to display hello world */
Groovy 的分号
;
分号,可以用来区分不同的代码块。
在 Groovy 编写中可以,可以省略分号符
Groovy 的标识符
和 Java 一样,标识符就是变量名,声明规则和 Java 一样,可以以字母开头,美元或下划线。但不能以数字开头。
Groovy 的关键字
大部分关键字和 Java 中的用法一样
as | assert | break | case |
---|---|---|---|
catch | class | const | continue |
def | default | do | else |
enum | extends | false | Finally |
for | goto | if | implements |
import | in | instanceof | interface |
new | pull | package | return |
super | switch | this | throw |
throws | trait | true | try |
while |
数据类型
Groovy 的内置数据类型和 Java 一样有8种。byte、short、int、long、float、double、char、boolean
字符串:String
并且都有其对应的封装类
变量
变量也和 Java 一样,除了使用基本数据类型和引用类型,还可以使用def
动态数据类型来声明变量。
// 和java的区别就是多了,def动态类型
def a = 1; // 在编译时会自动转化为int
def a = 'aa';
运算符
大部分运算符和 Java 一样,如:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符
与 Java 不同点在于,新增了 范围运算符
def range = 0..5
范围运算符通过..
来指定其开始和结束的范围。
上面示例就简单的定义了一个,从0到5的范围。
class Example { static void main(String[] args) { def range = 5..10; // 定义一个5~10的范围println(range); // 打印范围println(range.get(2)); // 取范围中是数据}
}
运行
[5, 6, 7, 8, 9, 10]
7
可以发现,范围变量,本质就是封装了一层数组。在操作时,通过其下标进行存取。
运算符优先级
运算符 | 名称 |
---|---|
++ ,-- ,+ ,-
|
预增/减(自增/减),一元加,一元减 |
* , / , %
|
乘法,除法,取模 |
+ ,-
|
加法,减法(二元) |
== ,!= , <=>
|
等于,不等于,比较运算符 |
&
|
二进制/位运算符与 |
^
|
二进制/位异或 |
` | ` |
! | 逻辑非 |
&&
|
逻辑与 |
` | |
= ,+= ,-= ,*= ,/= ,%= ,**=
|
各种赋值运算符 |
循环
Groovy 中的循环和 Java 中一样,包含循环跳出和结束循环等
while、for、break、continue
不同之处
在 Java 中我们常常使用foreach
来遍历
for(String str : strList){...
}
而在 Groovy 中提供了for in
语句,其使用方法和 Java 一样,只是关键字不同
for(def str in strList){println(str);
}
条件语句
Groovy 中的条件语句和 Java 中的一样,其关键字如下
if、else、switch
等
包括其嵌套使用等
方法
在 Groovy 中,方法的返回类型可以是 def 类型,而且在定义方法参数时,可以不必显示的定义参数的具体类型。
其方法修饰符默认为 public,可以添加其它修饰符,和 Java一样,默认 public 可以不用写
无参方法
def methodName() { //Method code
}
有参方法
def methodName(parameter1, parameter2, parameter3) { // Method code goes here
}
具体示例
class Example {static void sum(int a,int b) {int c = a+b;println(c);} static void main(String[] args) {sum(10,5);}
}
输出 15
默认参数值
在 Groovy 中,定义方法参数时,可以指定其参数的默认值,如果在调用此方法时有传入值,则使用传入值,否则使用默认值
class Example { static void sum(int a,int b = 5) { // 参数b的默认值为5int c = a+b; println(c); } static void main(String[] args) {sum(6); // 我们在调用时,只传入了一个参数}
}
输出 11
因为参数 b 有默认值,所以我们在使用时,可以选择传或不传参数 b
如果调用时,传入参数 b,则在计算时,会使用我们传入的值
class Example {static void sum(int a,int b = 5) {int c = a+b;println(c);} static void main(String[] args) {sum(6,6); // 传入参数b}
}
输出 12
无参调用
class test {static void main(String[] args){sun() // 无参调用}static void sun(a = 1,b = 2){println(a+b)}
}
输出 3
**注意:**如果方法没有默认值,在调用时,必须传入参数。
文件 I/O
Groovy 的IO除了使用 Java 的 API 以外,还提供了辅助类供我们使用
标准 Java 类
- java.io.File
- java.io.InputStream
- java.io.OutputStream
- java.io.Reader
- java.io.Writer
读取文件
可以使用 Groovy 提供的 File 类中的 eachLine 方法来快速读取文本文件的每一行
import java.io.File
class Example { static void main(String[] args) { new File("E:/Example.txt").eachLine { line -> println "line : $line" } }
}
如果想将文件的整个内容作为字符串获取,可以使用文件类的 text 属性
class Example { static void main(String[] args) { File file = new File("E:/Example.txt") println file.text }
}
写入文件
在写入文件时,也提供了对应的写入辅助
import java.io.File
class Example { static void main(String[] args) { new File('E:/','Example.txt').withWriter('utf-8') { writer -> writer.writeLine 'Hello World' } }
}
获取文件大小
可以通过 File 类的 length 属性进行获取
class Example {static void main(String[] args) {File file = new File("E:/Example.txt")println "The file ${file.absolutePath} has ${file.length()} bytes"}
}
测试文件是否为目录
class Example { static void main(String[] args) { def file = new File('E:/') println "File? ${file.isFile()}" println "Directory? ${file.isDirectory()}" }
}// 输出
File?
Directory? True
创建目录
class Example {static void main(String[] args) {def file = new File('E:/Directory')file.mkdir() // 如果文件夹不存在则创建}
}
删除文件
class Example {static void main(String[] args) {def file = new File('E:/Example.txt')file.delete()}
}
复制文件
class Example {static void main(String[] args) {def src = new File("E:/Example.txt")def dst = new File("E:/Example1.txt")dst << src.text}
}
复制文件使用 <<
特殊符号即可进行复制,
代码解释:将创建文件 Example1.txt,并将文件 Example.txt 的所有内容复制到此文件。
获取目录所在驱动器
class Example { static void main(String[] args) { def rootFiles = new File("test").listRoots() // 获取驱动器列表rootFiles.each { file -> println file.absolutePath // 遍历并打印}}
}
列出指定目录下的文件
class Example {static void main(String[] args) {new File("E:/Temp").eachFile() { // 使用 eachFile 获取目录下的所有文件file->println file.getAbsolutePath()}}
}
列出指定目录下的所有文件,包括递归处理子目录文件
class Example { static void main(String[] args) {new File("E:/temp").eachFileRecurse() { // 使用 eachFileRecurse 方法file -> println file.getAbsolutePath()}}
}
字符串
Groovy中的字符串可以用单引号('),双引号(“)或三引号(" ')括起来。
class test {static void main(String[] args){String a = 'Hello Single';String b = "Hello Double";String c = "'Hello Triple' + 'Multiple lines'"; // 注意如果单引号在外则不是字符串拼接println(a);println(b);println(c);}
}
输出
Hello Single
Hello Double
'Hello TripleMultiple lines'
也可以使用占位符去拼接字符串
name = 'Wangfang'
age = '18'// 占位符拼接的用法
print("my name is ${name},my age is ${age}.")
字符串索引
可以直接使用字符下标获取字符串中的字符
class Example { static void main(String[] args) { String sample = "Hello world"; println(sample[4]); // 打印第5个字符// 打印字符串最后一位字符println(sample[-1]); println(sample[1..2]);// 打印索引 1 ~ 2 的字符 println(sample[4..2]);// 反向打印,从索引4到索引2}
}
输出
o
d
el
oll
列表
Groovy 中的一个列表中的数据可以是任意类型。这 java 下集合列表有些不同,java 下的列表是同种类型的数据集合。
Groovy 列表可以嵌套列表。如 [1,2,[3,4,5],“aaa”]
Groovy 列表内置有反转方法 reverse()。调用 List.reverse() 可以实现列表反转。Groovy 列表内置有排序方法 sort()。调用 List.sort() 可以实现列表排序。
常用方法
添加
def list1 = [100, 101]
def list2 = [ 99,98,1]
println list2.plus(list1) //输出结果: [100, 101, 99, 98,1]
// list2.plus(list1) 也可以写成 list2 + list1
删除
def list1 = [12, 13]
def list2 = [11, 2, 33, 12, 13, 16]
println list2.minus(list1) //输出结果: [11, 2, 33, 16]
//list2.minus(list1) 也可以写成 list2 - list1
键值映射
在 Groovy 除了使用 Java 的Map集合,还可以显示的定义映射
['TopicName':'Lists','TopicName':'Maps'] //具有TopicName作为键的键值对的集合及其相应的值。
[:] // 空映射。
正则表达式
Groovy 中,使用正则表达式可以使用 ~
符号来判断
'Groovy' =~ 'Groovy'
'Groovy' =~ 'oo'
'Groovy' ==~ 'Groovy'
'Groovy' ==~ 'oo'
'Groovy' =~ '∧G'
'Groovy' =~ 'G$'
'Groovy' =~ 'Gro*vy' 'Groovy' =~ 'Gro{2}vy'
traits 特征
在 Groovy 中可以定义用 traits 修饰的类,表示特征类,它可以看作是有默认实现和状态的接口
trait Marks {void DisplayMarks() {println("Display Marks");}
}
我们可以使用 implement 关键字以类似于接口的方式实现 trait
trait Marks { void DisplayMarks() { // 特征里有一个实现方法println("Display Marks");}
} class Student implements Marks { // 可以像实现接口一样实现 trait 类int StudentIDint Marks1;
}class Example {static void main(String[] args) {Student st = new Student();st.StudentID = 1;st.Marks1 = 10; println(st.DisplayMarks());}
}
实现接口
Traits 类可以实现接口
interface Total { // 接口void DisplayTotal()
} trait Marks implements Total { // trait实现接口void DisplayMarks() {println("Display Marks");}void DisplayTotal() { // 实现接口的方法println("Display Total"); }
} class Student implements Marks { // 普通类实现trait类int StudentIDint Marks1;
} class Example {static void main(String[] args) {Student st = new Student();st.StudentID = 1;st.Marks1 = 10;println(st.DisplayMarks());println(st.DisplayTotal());}
}
属性
在 trait 类中也可以定义属性
interface Total {void DisplayTotal()
} trait Marks implements Total { //trait类int Marks1;void DisplayMarks() {this.Marks1 = 10;println(this.Marks1);}void DisplayTotal() {println("Display Total");}
}
多重实现
trait Marks {void DisplayMarks() {println("Marks1");}
} trait Total {void DisplayTotal() { println("Total");}
} class Student implements Marks,Total { // 具体类可以实现多个 特征类int StudentID
} class Example {static void main(String[] args) {Student st = new Student();st.StudentID = 1;println(st.DisplayMarks());println(st.DisplayTotal()); }
}
特征继承
特征类可以继承
trait Marks {void DisplayMarks() {println("Marks1");}
} trait Total extends Marks { //Total 继承 Marksvoid DisplayMarks() {println("Total");}
} class Student implements Total {int StudentID
}class Example {static void main(String[] args) {Student st = new Student();st.StudentID = 1;println(st.DisplayMarks());}
}
闭包
Groovy 的闭包,就是一个匿名的代码块,并且可以作为参数
class Example {static void main(String[] args) {def clos = {println "Hello World"}; // 简单的闭包clos.call();}
}// 输出
Hello World
上面的例子中,使用{代码块}
声明的被称为闭包,变量标识符可以通过 call 方法执行代码块
闭包中的形式参数
闭包代码块中,可以包含形式参数
class Example {static void main(String[] args) {def clos = {param -> println "Hello ${param}"};clos.call("World");}
}
还可以使用下面这种方式来进行定义,可以得到相同的结果
class Example {static void main(String[] args) {def clos = {println "Hello ${it}"};clos.call("World");}
}
it
参数,是Groovy定义的关键字,它被称为隐式单个参数
闭包和变量
在闭包代码块中,我们还可以使用变量,通过${变量名}
来使用
class Example { static void main(String[] args) {def str1 = "Hello";def clos = {param -> println "${str1} ${param}"}clos.call("World");// 改变star1的值str1 = "Welcome";clos.call("World");}
}
输出
Hello World
Welcome World
当我们改变str1变量值的时候,其内部的获取到的值,也会跟着改变。
闭包参数
闭包可以用作方法的参数
class Example { def static Display(clo) {// 执行闭包并传入参数 clo.call("Inner");} static void main(String[] args) {def str1 = "Hello";def clos = { param -> println "${str1} ${param}" }clos.call("World");// 将闭包传入到方法Example.Display(clos);}
}
输出
Hello World
Hello Inner
集合和字符串中的闭包
集合中,我们可以通过.each
函数来传入一个闭包,并将闭包应用于集合中每一个元素
class Example {static void main(String[] args) {def lst = [11, 12, 13, 14];lst.each {println it} // 传入闭包,it为单个隐式参数}
}
输出
11
12
13
14
键值对映射示例
class Example {static void main(String[] args) {def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"] mp.each {println it}mp.each {println "${it.key} maps to: ${it.value}"}}
}
输出
TopicName = Maps
TopicDescription = Methods in Maps
TopicName maps to: Maps
TopicDescription maps to: Methods in Maps
异常
在Groovy 中对异常处理的写法更为宽松:如果没有在该代码块内通过 try-catch 处理异常,那么该异常就会自动地向上级抛出,且无需在函数声明中使用 throws
主动定义它们。
其它语法
非空则调用语法
在java中判断为空
String maybeNull = "I'm Java";
if(maybeNull != null){System.out.println(nullString.length());
}
而在 Groovy 中可以使用?.
操作符来解决
String maybeNull = 'I\'m groovy'
print(maybeNull?.length())
精简的Bean
在编写bean时,可以使用def来表明其属性,不推荐
class Student_{final namedef ageStudent_(name,age){this.name = name this.age = age}
}s = new Student_('Wang Fang',23) //在使用时,会自动推导其属性的类型
省略构造器
class Student_{String nameInteger age
}// 没有实现 Student_(name,age) 构造器,但是可以直接使用
stu1 = new Student_(name: "Wang Fang",age: 12)// 同样,我们也没有手动实现 Student_(name) 构造器。
stu2 = new Student_(name:"Wang Fang")
在未指定构造器的情况下我们可以使用键值对的形式去构建对象。
如果没有提供构造器,我们不能使用下面的方式进行创建对象。
stu1 = new Student_("Wang Fang",12)
stu2 = new Student_("Wang Fang")
除非手动补上其对应的构造器
多重赋值
def swap(x, y) { return [y, x]
}Integer a, b
a = 10
b = 50// 通过多重赋值实现了两数交换
(a, b) = swap(a, b)
print("a=$a,b=$b")
如果方法 ( 函数 ) 返回的是一个数组,那么 Groovy 支持使用多个变量接收数组内的元素内容。
如果接收的变量和返回值个数不匹配时,Groovy会进行如下操作
- 如果接收的变量更多,那么会将没有赋值的变量赋为 null 。
- 如果返回值更多,那么多余的返回值会被丢弃。
多方法接口实现
在java中实现一个接口方法可以通过匿名或者Lambda的方式来实现
Calculator<Integer> calculator = new Calculator<Integer>() { // 匿名@Overridepublic Integer add(Integer a, Integer b) {return a + b;}
};Calculator<Integer> calculator = (a, b) -> a + b; // Lambda
在Groovy中使用如下方法来实现
def a = {a,b ->return a+b} as Calculator<Integer>
如果接口是多方法,则可以通过封装一层Map来实现
interface Calculator<T> {T add(T a, T b)T sub(T a, T b)
}def cal = [ //不同方法提供不同实现,通过as关键字来指定接口add: { a, b -> a + b }, sub: { a, b -> a - b }
] as Calculator<Integer>def c = cal.sub(1,2) //调用方法
print(c)
其它注解
@Canonical 替代 toString
@Canonical
// 如果不想打印 id 和 score,可以:
// @Canonical(excludes="id,score")
class Student {Integer idString nameInteger ageString majorInteger score
}// 如果没有此注解,打印的则是 Student@Hashcode
// 如果有注解,打印的则是 Student(1,"Wang Fang",20,"CS","score")
print new Student(id: 1,name:"Wang Fang",age: 20,major: "CS",score: 90.0d)
@Delegate 实现委托
使用 @Delegate
注解,在 Groovy 中实现方法委托非常容易。委托是继承以外的另一种代码复用的思路。在下面的代码块中,Manager 通过注解将 work()
方法委托给了内部的 worker 属性:
class Worker{void work(){print("worker is working exactly.")}
}// Manager 获得了 Worker 的公开方法,尽管 worker 属性本身是 private.
class Manager{@Delegate private Worker worker = new Worker() // 委托类
}// 检查 Manager 实例有没有 work 方法,没有就去委托 worker 执行此方法。
new Manager().work() // 调用委托类的方法
@Immutable 不可变对象
在java中创建不可变对象得使用final关键字,Groovy可以使用@Immutable注解来实现final修饰
@Immutable // 修饰student类为不可变
class Student_{String idString name
}def s = new Student_(id:"0001",name:"Wang Fang")print s
@Newify 注解
允许我们创建对象时,忽略new关键字
class Student{String idString name
}class Teacher{String idString name
}@Newify(Student)
def getStudent(){// 在函数内部创建 Student 时,可以省略掉 new 关键字。Student(id:"0001",name: "Wang Fang")
}// 多个类型使用数组的形式排列。
@Newify([Student,Teacher])
static def getStudentAndTeacher(){[Student(id:"0001",name:"Wang Fang"),Teacher(id: "0002",name:"Cheng Yu")]
}
@Singleton 单例模式
// 懒加载的单例模式,lazy 项是可选的。
@Singleton(lazy = true)
class TheUnique{{println "created only once"}
}// 通过 .instance 调用这个单例对象。
TheUnique.instance
注意 Groovy 的 == 符号
在 Java 中,==
可以比较两个基本数据类型的值,或者比较两个引用类型的 HashCode。
而在 Groovy 当中,这两者的混乱程度有所加剧:Groovy 的 ==
相当于是 Java 的 .equals()
方法或者是 compareTo()
方法 (见运算符重载的那个表格),而 Java 原始的 ==
语义在 Groovy 中变成了 is()
方法。
str1 = "111"
str2 = "222"// 相当于是 Java 语义中的 str1 == str2
str1.is(str2)// 相当于是 Java 语义中的 str1.equals(str2)
str1 == str2
如果比较的类实现了 Compareble
接口,那么 ==
的语义优先会选择 compareTo()
方法而非 equals()
方法。
Groovy 快速入门相关推荐
- Gradle用户指南(章9:Groovy快速入门)
Gradle用户指南(章9:Groovy快速入门) 你可以使用groovy插件来构建groovy项目.这个插件继承了java插件的功能,且扩展了groovy编译.你的项目可以包含groovy代码.ja ...
- Android Gradle(三)Groovy快速入门指南
本文首发于微信公众号「刘望舒」 原文链接:Groovy快速入门看这篇就够了 前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我 ...
- Gradle核心思想(三)Groovy快速入门指南
本文首发于微信公众号「刘望舒」 关联文章 Gradle核心思想(一)为什么现在要用Gradle? Gradle核心思想(二)Gradle入门前奏 Gradle核心思想(三)Groovy快速入门指南 G ...
- Gradle Groovy 快速入门
要构建一个 Groovy 项目,你需要使用 Groovy 插件.该插件扩展了 Java 插件,对你的项目增加了 Groovy 的编译功能. 你的项目可以包含 Groovy 源码,Java 源码,或者两 ...
- Groovy快速入门-12-Groovy如何读文件内容和写入文件
文件读写操作,在编程中经常需要去写的代码,同样在pipeline代码中,一些测试验证的代码也需要去读文件来判断下一步的动作,本篇来介绍如何读文件的groovy代码.然后简单介绍如何写入文件,写入文件比 ...
- android groovy方法,Android Gradle从入门到精通(三)Groovy快速入门指南
前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groovy的基础,要想学好Gradle,Groovy是必须要掌 ...
- Groovy快速入门指南
1.Groovy概述 Groovy是Apache 旗下的一种基于JVM的面向对象编程语言,既可以用于面向对象编程,也可以用作纯粹的脚本语言.在语言的设计上它吸纳了Python.Ruby 和 Small ...
- groovy if 判断字符串_Groovy快速入门看这篇就够了
原标题:Groovy快速入门看这篇就够了 来自:刘望舒(微信号:liuwangshuAndroid) 前言 在前面我们学习了和两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groov ...
- Spring Boot 2 快速教程:WebFlux 快速入门(二)
2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...
- Spring Boot 2.x基础教程:快速入门
点击蓝色"程序猿DD"关注我哟 来源:http://t./ <Star最多的Spring Boot教程继续更新了> 牛皮吹过了! Git仓库和博客专题页也改版完成! 是 ...
最新文章
- C语言socket accept()函数(提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符)
- linux qos 软件,linux下QOS:应用篇 - 博客 - 伯乐在线
- Microsoft宣布正式发布Linux on ASE
- Java IO: 字符流的Piped和CharArray
- 三星系统和鸿蒙系统,又一设备直升鸿蒙系统,现有操作系统被抛弃,和三星的想法一样!...
- 认清一个人,看这四点就够了
- 后端比android简单,android开发怎么少的了后端(下)
- https://gogs.io/
- 根据条件返回相应值 decode(条件,值1,翻译值1,值2,翻译值2,...值n,翻译值n,缺省值)...
- 腾讯 Github 全球贡献前十;三星可折叠手机售价 1.6 万;OpenTitan 正式开源|极客头条...
- Android 应用程序之间数据共享—ContentProvider
- OriginLab学生版激活码续期
- java的 jre是什么_Java中JRE介绍,JRE是什么
- 关于TC Games针对没有耳机接口的Type-C用户玩手游如何传音和语音
- 老九学堂 学习 C++ 第七、八天
- 身为程序员,就应该了解微服务的未来发展趋势:云原生应用架构
- 深度学习笔记(三十一)三维卷积及卷积神经网络
- 信息学奥赛一本通(题解目录)
- 打印机设置好共享名,单击确定,弹出0x000006d9错误
- linux 三剑客 之 awk
热门文章
- 赵小楼《天道》《遥远的救世主》深度解析(38)丁元英的“自嘲”和作者豆豆的深意
- 微信小程序云开发———云存储
- WEB前端缓存解决方案
- 2015年国内数据安全事件盘点
- 线性回归-误差项分析
- Ant design分析后台首页
- c语言程序设计的删除函数,详解C语言中的rename()函数和remove()函数的使用方法
- 最新的quartus ii、dsp builder、matlab版本匹配安装破解
- android系统应用更改内存,安卓root后必备神器:修改系统/清理内存神器
- os.system和os.popen函数的区别