文章目录

  • 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 快速入门相关推荐

  1. Gradle用户指南(章9:Groovy快速入门)

    Gradle用户指南(章9:Groovy快速入门) 你可以使用groovy插件来构建groovy项目.这个插件继承了java插件的功能,且扩展了groovy编译.你的项目可以包含groovy代码.ja ...

  2. Android Gradle(三)Groovy快速入门指南

    本文首发于微信公众号「刘望舒」 原文链接:Groovy快速入门看这篇就够了 前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我 ...

  3. Gradle核心思想(三)Groovy快速入门指南

    本文首发于微信公众号「刘望舒」 关联文章 Gradle核心思想(一)为什么现在要用Gradle? Gradle核心思想(二)Gradle入门前奏 Gradle核心思想(三)Groovy快速入门指南 G ...

  4. Gradle Groovy 快速入门

    要构建一个 Groovy 项目,你需要使用 Groovy 插件.该插件扩展了 Java 插件,对你的项目增加了 Groovy 的编译功能. 你的项目可以包含 Groovy 源码,Java 源码,或者两 ...

  5. Groovy快速入门-12-Groovy如何读文件内容和写入文件

    文件读写操作,在编程中经常需要去写的代码,同样在pipeline代码中,一些测试验证的代码也需要去读文件来判断下一步的动作,本篇来介绍如何读文件的groovy代码.然后简单介绍如何写入文件,写入文件比 ...

  6. android groovy方法,Android Gradle从入门到精通(三)Groovy快速入门指南

    前言 在前面我们学习了为什么现在要用Gradle?和Gradle入门前奏两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groovy的基础,要想学好Gradle,Groovy是必须要掌 ...

  7. Groovy快速入门指南

    1.Groovy概述 Groovy是Apache 旗下的一种基于JVM的面向对象编程语言,既可以用于面向对象编程,也可以用作纯粹的脚本语言.在语言的设计上它吸纳了Python.Ruby 和 Small ...

  8. groovy if 判断字符串_Groovy快速入门看这篇就够了

    原标题:Groovy快速入门看这篇就够了 来自:刘望舒(微信号:liuwangshuAndroid) 前言 在前面我们学习了和两篇文章,对Gradle也有了大概的了解,这篇文章我们接着来学习Groov ...

  9. Spring Boot 2 快速教程:WebFlux 快速入门(二)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  10. Spring Boot 2.x基础教程:快速入门

    点击蓝色"程序猿DD"关注我哟 来源:http://t./ <Star最多的Spring Boot教程继续更新了> 牛皮吹过了! Git仓库和博客专题页也改版完成! 是 ...

最新文章

  1. C语言socket accept()函数(提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符)
  2. linux qos 软件,linux下QOS:应用篇 - 博客 - 伯乐在线
  3. Microsoft宣布正式发布Linux on ASE
  4. Java IO: 字符流的Piped和CharArray
  5. 三星系统和鸿蒙系统,又一设备直升鸿蒙系统,现有操作系统被抛弃,和三星的想法一样!...
  6. 认清一个人,看这四点就够了
  7. 后端比android简单,android开发怎么少的了后端(下)
  8. https://gogs.io/
  9. 根据条件返回相应值 decode(条件,值1,翻译值1,值2,翻译值2,...值n,翻译值n,缺省值)...
  10. 腾讯 Github 全球贡献前十;三星可折叠手机售价 1.6 万;OpenTitan 正式开源|极客头条...
  11. Android 应用程序之间数据共享—ContentProvider
  12. OriginLab学生版激活码续期
  13. java的 jre是什么_Java中JRE介绍,JRE是什么
  14. 关于TC Games针对没有耳机接口的Type-C用户玩手游如何传音和语音
  15. 老九学堂 学习 C++ 第七、八天
  16. 身为程序员,就应该了解微服务的未来发展趋势:云原生应用架构
  17. 深度学习笔记(三十一)三维卷积及卷积神经网络
  18. 信息学奥赛一本通(题解目录)
  19. 打印机设置好共享名,单击确定,弹出0x000006d9错误
  20. linux 三剑客 之 awk

热门文章

  1. 赵小楼《天道》《遥远的救世主》深度解析(38)丁元英的“自嘲”和作者豆豆的深意
  2. 微信小程序云开发———云存储
  3. WEB前端缓存解决方案
  4. 2015年国内数据安全事件盘点
  5. 线性回归-误差项分析
  6. Ant design分析后台首页
  7. c语言程序设计的删除函数,详解C语言中的rename()函数和remove()函数的使用方法
  8. 最新的quartus ii、dsp builder、matlab版本匹配安装破解
  9. android系统应用更改内存,安卓root后必备神器:修改系统/清理内存神器
  10. os.system和os.popen函数的区别