Groovy

1 Groovy的诞生

请添加图片描述

Groovy是一门几经重生的语言,该语言由James Stracham和Bob McWhirter于2003年启动开发,之后于2004年3月成为JSR241(Java Specification Request,即Java规范请求)。不久因为存在一些困难和问题几近放弃。Guillaume Laforge和Jeremy Rayner决定再次努力,首先修复了一些bug,同时使语言稳定下来,后来他们又邀请了一些有丰富经验的开发者加入他们的团队,最终一个形成了一个充满生气的开发者社区,并使Groovy重获新生。

Groovy的第一个版本于2007年1月发布,目前最新版本是4.0.5,在这之前很多组织已经将Groovy应用于商业项目,大量使用Groovy语言的时机已经成熟。

2 为何选择Groovy

Groovy是用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。

Groovy是JVM的一个替代语言(Groovy 可以在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。

作为Java程序员我们不必要切换到一门自己完全不熟悉的语言上,使用Groovy感觉就好像对已经熟知的Java作了一些扩展。

当前很多脚本语言都可以在JVM上运行,除了Groovy外,还有JRuby、JPython、BeanShell和JavaScript等。基于下面的一些特点让我们选择了Groovy:

  • 易于掌握
  • 遵循Java语义
  • 动态语言
  • 扩展了JDK

如果你是一个Java程序员,你可以把Java代码当作Groovy代码来运行,在你学习了Groovy之后,把它修改为Groovy风格的代码,这意味着学习越来非常容易。例如,在Java中我们写一个for循环:

for(int i=0;i<10;i++){
    ...
}

用Groovy改写如下:

10.times{
	...
}

在使用Groovy编程时,Java有的Groovy几乎都有。Groovy同样扩展了java.lang.Object类,Groovy类就是Java类,Java语义都保留下来了,所以使用Groovy编写的表达式和语句,对于Java程序员而言,理解它没有任何障碍。

选择Groovy的另一个原因是它是动态语言。同为动态语言还包括Smalltalk、Python、Ruby、JavaScript等。所谓动态语言是指在运行时扩展程序,包括修改类型、行为、对象结构。静态语言在编译时做的事情,动态语言可以在运行时做。作为开发者通过使用动态语言,可以让我们的工作更有效率。更高的效率意味着可以快速创建一些应用,从而得到测试人员、项目经理、客户代表的反馈,而这一切以会使我们更加敏捷。

实时效果反馈

1. 选择Groovy的原因不包括下面哪个?

A 易于掌握

B 动态语言

C 只能在JVM上运行

D 运行速度快

答案

1=>C

3 在Windows下安装Groovy

进入https://groovy.apache.org/download.html

请添加图片描述

点击Download4.0.5按钮,开始下载,下载完成后解压apache-groovy-sdk-4.0.5.zip文件。

配置环境变量

打开Window下环境变量设置窗口,新建一个名为GROOVY_HOME的环境变量,变量的值是解压后Groovy sdk的目录,我们可以把它放在c:\program files\目录下,如下图:
在这里插入图片描述

选中Path变量进行编辑

在这里插入图片描述

在Path变量中添加%GROOVY_HOME%\bin

在这里插入图片描述

完成后点击“确定”。

打开window的命令提示窗口,输入

C:\Users\a>groovy -v

如果出现以下版本信息,则安装成功。

C:\Users\a>groovy -v
Groovy Version: 4.0.5 JVM: 1.8.0_291 Vendor: Oracle Corporation OS: Windows 10

4 使用Groovy控制台运行

安装完成后,在bin目录下有一个GroovyConsole.bat文件,双击打开,可以在里面编写并执行Groovy程序。
在这里插入图片描述
在这里插入图片描述

Window系统用户按Ctrl+Enter或Ctrl+R执行代码。

5 在IntelliJ Idea中运行

在File菜单下点击new project...,选择Groovy类型的项目,并设置好Groovy library,点击

Next填写项目名称及路径,完成后点击Finish

在这里插入图片描述
在这里插入图片描述

点击Tools菜单下的Groovy Console...,开始编写程序
在这里插入图片描述
在这里插入图片描述

完成后,点击红色小方块中的运行按钮执行程序,运行结果显示在下方的控制台区域。

6 Groovy与Java的关系

在这里插入图片描述

我们先从一个Java代码编写的例子开始,同时它也是Groovy代码,保存在一个后缀为groovy的文件中。

//Java代码
public class GrvTest01 {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println("ho");
        }
        System.out.println("Hello Groovy");
    }
}

在window命令提示窗口中使用groovy命令执行这段程序

在这里插入图片描述

可以看到,Java编写的代码在groovy中可以正常运行,实际只保留for循环和输出语句,其它的都可以不要,依然可以正常运行。例如:

for (int i = 0; i < 10; i++) {
    System.out.println("ho");
}
System.out.println("Hello Groovy");

把它保存为GrvTest02.groovy,执行groovy运行

在这里插入图片描述

可以看到运行结果与前面的完全一样,但代码要简洁得多。甚至可以更进一步,可以简化成下面的代码,效果也是一样的

for(i in 1..10){println 'ho'}
println 'Hello Groovy'

我们把它保存为GrvTest03.groovy,然后在命令行执行

在这里插入图片描述

结果和前面一样,而且代码更轻便了

GDK介绍

Groovy虽然支持Java的语法但它并没有强迫我们学习新的类和库,而是通过向JDK中各种类添加方法,所以说Groovy扩展了JDK,这些扩展称之为GDK(Groovy JDK)。

Java中可以使用java.lang.process与系统级进程进行交互,例如,我们在代码中调用git的help命令并把help的内容打印出来,用Java的实现代码如下:

public class ExceuteProcess {
    public static void main(String[] args) {
        try {
            Process process = Runtime.getRuntime().exec("git help");
            BufferedReader result = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while((line = result.readLine())!=null){
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下图:

在这里插入图片描述

Groovy通过在java.lang.String类上添加一个execute()方法,使这一切变得很简单。

println "git help".execute().text

运行后输出的结果与上面的一模一样。

在这里插入图片描述

通过此例,我们看到GDK的扩展功能使程序员的编码工作更为轻松,但这仅仅是GDK的一点皮毛。

实时效果反馈

1. 关于Groovy描述不正确的是?

A 同时运行静态和动态类型

B Groovy和Java很相似

C Groovy是轻量级的Java,且更为易用

D Groovy直接使用JDK,没有进行任何扩展

答案

1=>D

7 Groovy的数据类型

在这里插入图片描述

7.1 Groovy的保留字

abstractassertbreakcase
catchclassconstcontinue
defdefaultdoelse
enumextendsfinalfinally
forgotoifimplements
importinstanceofinterfacenative
newnullnon-sealedpackage
publicprotectedprivatereturn
staticstrictfpsuperswitch
synchronizedthisthreadsafethrow
throwstransienttrywhile

一般来说这些保留字不能用于定义变量、方法。如果用双引号引起来,也可以作为方法名,但不推荐这么做。例如:

 def "abstract"() { true }

7.2 标识符

Groovy标识符以字母、美元符号或下划线开头,不能以数字开头。下面是合法的标识符:

def name
def item3
def with_underscore
def $dollarStart

下面是非法的标识符

def 3tier
def a+b
def a#b

1. 下面Groovy的标识符定义正确的是?

A #ab

B -m_user

C 3a_b

D $ab

答案

1=>D

7.3 字符串

Groovy允许实例化java.lang.String类来定义一个字符串对象,同样地,也可以通过实例化groovy.lang.GString类定义一个字符串对象,两者可以混合使用。

例如,用单引号引起来的字符串

'a single-quoted string'

三个单引号引起来的字符串

'''a triple-single-quoted string'''
def aMultilineString = '''line one
line two
line three'''		//'''定义的字符串可以折行,无需连接或转义字符

说明:用单引号或三个单引号定义的字符串不支持混合编程

双引号引起来的字符串

"a double-quoted string"

在Groovy中使用${}作为占位符,占位符里面代表一个表达式的值,例如:

def name = 'Guillaume' 			// a plain string
def greeting = "Hello ${name}"

assert greeting.toString() == 'Hello Guillaume'

三个双引号引起来的字符串

用"""引号引起来的字符串行为上和双引号引起来的字符串是一样的,不同之处在于它代表多行字符串,就像三个单引号定义的字符串。例如:

def name = 'Groovy'
def template = """
    Dear Mr ${name},

    You're the winner of the lottery!

    Yours sincerly,

    Dave
"""

Groovy字符串总结

字符串名称语法是否可以混用是否多行转义字符
单引号的'…'\
三个单引号的'''…'''\
双引号的"…"\
三个双引号的"""…"""\
斜线的/…/\

1. 关于Groovy的字符串说法不正确的是?

A groovy字符串种类比Java字符串更多

B 所有groovy字符串种类都可以与Java混合使用

C groovy字符串都是有序序列,可以通过下标访问单个字符

D 三引号定义的字符串用于定义多行字符串变量

答案

1=>B

7.4 数值类型

在这里插入图片描述

Groovy的数值型包括整数型(Integer)和小数型(decimal)两种,整型又包括以下几种:

  • byte
  • char
  • short
  • int
  • long
  • java.math.BigInteger

整数型

//基本类型
byte  b = 1
char  c = 2
short s = 3
int   i = 4
long  l = 5

//无限精度型
BigInteger bi =  6

使用def关键字定义数值型变量

def a = 1	//整型
assert a instanceof Integer

// 定义整型最大值 Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer

// 定义整型最大值+1,Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long

// 定义long型最大值 Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long

// 定义long型最大值+1,Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger

定义二进制数,以0b为前缀

int xInt = 0b10101111
assert xInt == 175		//整型

short xShort = 0b11001001
assert xShort == 201 	//短整型

byte xByte = 0b11
assert xByte == 3 		//字节型

long xLong = 0b101101101101
assert xLong == 2925l	//long型

BigInteger xBigInteger = 0b111100100001
assert xBigInteger == 3873g		//BigInteger型

int xNegativeInt = -0b10101111
assert xNegativeInt == -175		//负整数

定义八进制数,以0为前缀

int xInt = 077
assert xInt == 63

short xShort = 011
assert xShort == 9 		

byte xByte = 032
assert xByte == 26

long xLong = 0246
assert xLong == 166l

BigInteger xBigInteger = 01111
assert xBigInteger == 585g

int xNegativeInt = -077
assert xNegativeInt == -63

定义16进制数,以0x为前缀

int xInt = 0x77
assert xInt == 119

short xShort = 0xaa
assert xShort == 170 

byte xByte = 0x3a
assert xByte == 58

long xLong = 0xffff
assert xLong == 65535l

BigInteger xBigInteger = 0xaaaa
assert xBigInteger == 43690g

int xNegativeInt = -0x77
assert xNegativeInt == -119

小数型(decimal)

在这里插入图片描述

以下定义的变量都属于小数型

// 基本类型
float  f = 1.234
double d = 2.345

// 带有精度的小数类型
BigDecimal bd =  3.456

可以使用科学计数法表示相应类型的数值,例如:

assert 1e3  ==  1_000.0
assert 2E4  == 20_000.0
assert 3e+1 ==     30.0
assert 4E-2 ==      0.04
assert 5e-1 ==      0.5

Groovy支持用下划线对数字进行分割,使得数字更容易识别

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010

各种类型数值的后缀

类型后缀
BigIntegerG or g
LongL or l
IntegerI or i
BigDecimalG or g
DoubleD or d
FloatF or f

例如:

assert 42I == Integer.valueOf('42')
assert 42i == Integer.valueOf('42') // 小写i可读性更好
assert 123L == Long.valueOf("123") // 大写L可读性更好
assert 2147483648 == Long.valueOf('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert .321 == new BigDecimal('.321')
assert 1.200065D == Double.valueOf('1.200065')
assert 1.234F == Float.valueOf('1.234')
assert 1.23E23D == Double.valueOf('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal

不同类型数值进行算术运算的规则

对于二元运算符,两个不同类型的数值进行运算后它们的结果按照以下规则确定

  • 对于byte、char、short、int这几种类型之间运算的结果为int
  • 涉及long与byte、char、short、int之间运算的结果为long
  • 涉及BigInteger与其它类型数值之间的运算结果为BigInteger
  • BigDecimal与byte、char、short、int之间的运算结果为BigDecimal
  • float、double与BigDecimal之间的运算结果为double
  • 两个BigDecimal之间的运算结果为BigDecimal

1. 关于Groovy的数值型说法不正确的是?

A 数值型包括整数型和小数型

B 二进制、八进制、16进制可以用于表示小数类型

C 小数型包括float、double、BigDecimal三种类型

D 整数型包括byte、char、short、int、long和Java.math.BigInteger类型

答案

1=>B

7.5 布尔型

包含true、false两个基本布尔值,下面是定义布尔型变量的例子:

def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true

7.6 集合类型

在这里插入图片描述

Groovy没有自己的集合类型,它的List类型实际上用的就是JDK中的java.util.List包。当我们定义一个集合对象,Groovy默认采用Java.util.ArrayList类型。

Groovy使用,把集合中的元素分隔开,外面用[]进行包裹。下面是定义集合对象的例子:

def numbers = [1, 2, 3]         
assert numbers instanceof List  
assert numbers.size() == 3      

也可以在集合中放置不同类型的元素,例如:

def heterogeneous = [1, "a", true]

默认定义的集合对象属于Java.util.ArrayList类,也可以用as运算符,强制定义List接口的其它实现类的对象,例如:

def arrayList = [1, 2, 3]
assert arrayList instanceof java.util.ArrayList

def linkedList = [2, 3, 4] as LinkedList    
assert linkedList instanceof java.util.LinkedList

LinkedList otherLinked = [3, 4, 5]          
assert otherLinked instanceof java.util.LinkedList

访问List集合中的元素使用[]下标运算符,其中的数值可以是正值也只可以是负值,例如:

def letters = ['a', 'b', 'c', 'd']

assert letters[0] == 'a'     
assert letters[1] == 'b'

assert letters[-1] == 'd'    
assert letters[-2] == 'c'

letters << 'e'     //使用左移运算符,在集合末尾添加元素
assert letters[4] == 'e'
assert letters[-1] == 'e'

Groovy可以定义多维集合,例如:

def multi = [[0, 1], [2, 3]]     
assert multi[1][0] == 2          	//第1个集合中的第0个元素

1. 关于Groovy的集合类型说法不正确的是?

A Groovy集合类对象中的元素类型必须相同

B Groovy集合类型默认使用Java.util.List中的类

C 可以像访问数组元素那样访问集合中的元素

D 可以使用as运算符强制转为其它List接口的实现类

答案

1=>A

7.7 数组

在这里插入图片描述

Groovy中数组和集合的表示方式相同,也就是说Groovy复用list的表示形式来表示数组,但必须显式的声明数组的类型,例如:

String[] arrStr = ['Ananas', 'Banana', 'Kiwi']
assert arrStr instanceof String[]    	//断言为true
assert !(arrStr instanceof List)		//断言为true

使用as运算符,强制转为要定义的类型

def numArr = [1, 2, 3] as int[] 
assert numArr instanceof int[]       

也可以定义多维数组

def matrix3 = new Integer[2][3]  //定义一个二维数组,并指定元素个数
assert matrix3.size() == 2		 //维数为2

Integer[][] matrix2              //声明时不指定数组元素个数     
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]

访问数组元素时按照和list一样的方式,使用下标运算符[],例如:

String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
assert names[0] == 'Cédric'     //访问第0个元素

names[2] = 'Blackdrag'          //给第二个元素重新赋值
assert names[2] == 'Blackdrag'

Java风格数组初始化

//java风格数组初始化方式
def primes = new int[] {2, 3, 5, 7, 11}
assert primes.size() == 5 && primes.sum() == 28

def pets = new String[] {'cat', 'dog'}
assert pets.size() == 2 && pets.sum() == 'catdog'

//Groovy定义初始化数组的方式
String[] groovyBooks = [ 'Groovy in Action', 'Making Java Groovy' ]
assert groovyBooks.every{ it.contains('Groovy') }

1. 关于Groovy的数组类型说法不正确的是?

A Groovy数组对象的定义和集合对象的定义形式相同

B Groovy数组采用下标运算符[]访问元素或给元素赋值

C Groovy也支持采用大括号的形式初始化数组

D 数组里所有元素的类型可以不相同

答案

1=>D

7.8 map类型

在这里插入图片描述

Groovy使用中括号定义一个map,map中的key/value对用逗号分割,例如:

def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']   

assert colors['red'] == '#FF0000'    
assert colors.green  == '#00FF00'   

colors['pink'] = '#FF00FF'      //使用[]增加一个新的key/value  
colors.yellow  = '#FFFF00'  	//也可使用.新增一个key/value

说明:

Groovy定义的map对象实际上是Java.util.LinkedHashMap类的实例

key值不光可以用string也可以用其它数据类型,比如,整型

def numbers = [1: 'one', 2: 'two']

下面的例子中用key这个变量定义了一个key,它的值为name,但Groovy会认为,map中的key是变量本身而不是赋于它的值。

def key = 'name'
def person = [key: 'Guillaume']      

assert !person.containsKey('name')   
assert person.containsKey('key')     

如果要给map里传变量名,必须使用这种形式(变量名),例如:

person = [(key): 'Guillaume']        

assert person.containsKey('name')    
assert !person.containsKey('key')

1. 关于Groovy的map类型说法不正确的是?

A map使用的是Java.util.LinkedHashMap

B map m1 = [‘name’:‘Jack’,‘age’:18,‘sex’:‘male’]这是一个正确的map定义

C map中的key值不仅仅是String类型也可以是其它类型

D 可以通过下标运算符[]来访问或新增map中的元素

答案

1=>B

8 Groovy的运算符

在这里插入图片描述

8.1 算术运算符

运算符作用备注
+同时也是一元运算符,如:+4
-同时也是一元运算符,如:-2
*
/intdiv()专门用于整数相除
%取余
**次幂例如:2 ** 3 =8

赋值运算符

  • +=
  • -=
  • *=
  • /=
  • %=
  • **=
def a = 4
a += 3		//等价于a=a+3

assert a == 7

def b = 5
b -= 3		//等价于b=b-3

assert b == 2

def c = 5
c *= 3		//等价于c=c*3

assert c == 15

def d = 10
d /= 2		//等价于d=d/2

assert d == 5

def e = 10
e %= 3		//等价于e=e%3

assert e == 1

def f = 3
f **= 2		//等价于f=f**2

assert f == 9

1. 下列表达式结果错误的是?

A 2++*3的结果等于6

B 2–*3的结果等于6

C ++2+3的结果等于6

D --1-1的结果等于0

答案

1=>D

8.2 关系运算符

运算符作用
==相等
!=不等
<小于
<=小于等于
>大于
>=大于等于
===完全等于 (Since Groovy 3.0.0)
!==不完全等于 (Since Groovy 3.0.0)
assert 1 + 2 == 3
assert 3 != 4

assert -2 < 3
assert 2 <= 2
assert 3 <= 4

assert 5 > 1
assert 5 >= -2

下面是groovy判断===(全等)和!==(不全等)运算符的示例:

import groovy.transform.EqualsAndHashCode

@EqualsAndHashCode
class Creature { String type }

def cat = new Creature(type: 'cat')
def copyCat = cat
def lion = new Creature(type: 'cat')

assert cat.is(copyCat)  // Groovy的is()方法判断两个对象是否相等
assert cat === copyCat  // ===是is()的简洁操作符
assert cat !== lion     // negated operator shorthand

8.3 逻辑运算符

Groovy提供了三种逻辑运算符用于布尔表达式,分别是:

  • &&:逻辑与
  • ||:逻辑或
  • !:逻辑非

例如:

assert true && true
assert true || false 
assert !false

注:逻辑非运算符优先级高于逻辑与&&,逻辑与运算符&&优先级高于逻辑或||,例如:

assert (!false && false) == false
assert true || true && false

短路运算规则

逻辑与&&和逻辑或||都支持短路运算,对于||只要左边的操作数为true,不需要再判断右边的操作数就知道整个表达式的结果为true。对于&&只要左边的操作数为false,不需要再判断右边的操作数就知道整个表达式的结果为false。

1. 下列逻辑运算符优先级正确的是?

A !>&&>||

B &&>||>!

C ||>!>&&

D &&>!>||

答案

1=>A

8.4 位运算符和位移运算符

Groovy的位运算符如下:

  • &: 按位与
  • |: 按位或
  • ^: 按位异或
  • ~: 按位取反

位运算符的操作数为整型数值,包括byte、short、int、long、BigInteger。如果操作数的类型是BigInteger那么返回结果的类型也是BigInteger;如果操作数是int型,返回结果也是int型;如果操作数是long型,返回结果也是long型。

Groovy提供了三种位移运算符,分别是:

  • <<: 左移运算符
  • >>: 右移运算符
  • >>>: 右移无符号运算符
assert 12.equals(3 << 2)           
assert 24L.equals(3L << 3)         
assert 48G.equals(3G << 4)     

1. 下列关于位运算和位移运算规则说法正确的是?

A 位运算中一个参数的类型为BigInteger,那么运算结果的类型也是BigInteger

B 位运算中两个参数类型分别为Long和BigInteger,那么运算结果的类型是Long

C 位运算中两个参数类型分别为Long和int,那么运算结果的类型是int

D 位移运算中的左侧操作数的类型只能是byte、short、int、long、BigInteger

答案

1=>A

8.5 条件运算符

条件运算符可用于取代if-else判断,例如:

if (string!=null && string.length()>0) {
    result = 'Found'
} else {
    result = 'Not found'
}

利用条件运算符可以写成如下形式:

result = (string!=null && string.length()>0) ? 'Found' : 'Not found'

从Groovy3.0开始,引入了elvis操作符,也就是条件运算符的简便形式,例如:

displayName = user.name ? user.name : 'Anonymous'   //正常形式
displayName = user.name ?: 'Anonymous'       //elvis操作符

8.6 对象运算符

安全导航运算符(safe navigation operator)

主要作用为避免出现NullPointerException异常,如果出现空指针异常,使用安全导航运算符将返回null,而不是抛出异常。例如:

def person = Person.find { it.id == 345 }  //调用find方法查找
def name = person?.name  //如果查找的对象不存在,返回null    
assert name == null                          

直接字段访问运算符(Direct field access operator)

使用该运算符可以不用调用get方法而直接获取字段的值,例如:

class User {
    public final String name                 
    User(String name) { this.name = name}
    String getName() { "Name: $name" }       
}
def user = new User('Bob')
assert user.name == 'Name: Bob'
assert user.@name == 'Bob'		//使用.@字段名代替getter方法

方法引用运算符(method reference operator)

方法引用运算符形如两个冒号::,目的就是调用方法。例如:

assert 6G == [1G, 2G, 3G].stream().reduce(0G, BigInteger::add)

调用BigInteger实例的add方法,给每个元素减0,结果仍然不变。

assert [4G, 5G, 6G] == [1G, 2G, 3G].stream().map(3G::add).collect(toList()) 

3G对象属于BigInteger类型,调用它的add方法,给每个元素加3。

assert [1, 2, 3] == ['1', '2', '3'].stream().map(Integer::new).collect(toList())
def result = [1, 2, 3].stream().toArray(Integer[]::new)

第1行代码使用方法引用运算符调用Integer类的构造方法创建Integer类对象;第2行代码同样地,调用数组类的构造方法创建一个数组对象。

1. 下列关于对象运算符说法错误的是?

A 对象运算符包括null-safe、直接字段访问运算符和方法引用运算符

B nll-safe也称方法安全导航,目的是防止程序抛出NullPointerException

C 直接字段访问运算符相当于调用了字段的get方法来获取字段值

D 方法引用运算符只能调用静态方法而不能调用类的实例方法

答案

1=>D

8.7 正则表达式运算符

~规则运算符

~运算符提供了一种简单的方式来创建一个java.util.regex.Pattern对象,例如:

import java.util.regex.Pattern

def p = ~/foo/
assert p instanceof Pattern

=~查找运算符

=~运算符用于创建一个java.util.regex.Matcher对象,例如:

//定义一个字符串
def text = "some text to match"
//使用=~运算符创建一个Matcher对象,匹配文本中的match单词
def m = text =~ /match/        

==~匹配运算符

==~运算符和=~运算符功能相似,只是返回结果不同,前者返回布尔值,后者返回Matcher对象。例如:

m = text ==~ /match/                                           
assert m instanceof Boolean                                   
if (m) {                                                       
    throw new RuntimeException("不是Boolean类")
}

1. 下列关于正则运算符说法错误的是?

A 正则运算符有规则运算符、查找运算符和匹配运算符

B 查找和匹配运算符功能相似,只是返回值类型不同

C 查找运算符返回一个布尔值

D 匹配运算符返回布尔值

答案

1=>C

9 Groovy程序的组成

在这里插入图片描述

Groovy提供了两种代码方式,一种是脚本一种是类,首先我们定义一个名为Main.groovy 的类。代码如下:

class Main {                                    
    static void main(String... args) {          
        println 'Groovy world!'                 
    }
}

与上面代码功能相同的脚本如下:

println 'Groovy world!'

脚本与类混合

上面的脚本实由groovy.lang.Script类编译成一个class文件,把脚本代码拷贝到groovy.lang.Script类的run方法中进行执行,实际运行的代码形如下面的内容:

import org.codehaus.groovy.runtime.InvokerHelper

class Main extends Script {                     
    def run() {                                 
        println 'Groovy world!'                 
    }
    static void main(String[] args) {           
        InvokerHelper.runScript(Main, args)     
    }
}

执行的步骤如下:

  • Main.class继承Script类
  • 把脚本的主体内容复制到run方法内
  • 然后自动生成main()方法,最后运行run()

方法

可以在脚本中定义方法,例如:

int fib(int n) {
    n < 2 ? 1 : fib(n-1) + fib(n-2)
}
assert fib(10)==89

创建的脚本类在编译后会把脚本中的所有方法装配到run方法中,这些对于用户来说都是透明的。

变量

在脚本中定义变量无需声明变量的类型,例如:

int x = 1
int y = 2
assert x+y == 3

上面的定义与如下代码等同:

x = 1
y = 2
assert x+y == 3

这两者在语义上有一些差别,上面的例子中声明的变量属于局部变量,只在run方法内部可见,而下面的无声明变量定义对于其它方法可见,这对于脚本与其它应用程序共享数据就显得很重要了。

1. 下列关于Groovy脚本与类的说法错误的是?

A 脚本其实也是类,经过编译后缀为.groovy

B groovy是一门脚本语言,使用脚本写法更简洁

C groovy类必须有一个static的main()方法

D groovy同时支持脚本和类,可以在类中调用脚本

答案

1=>A

10 Groovy面向对象

在这里插入图片描述

Groovy的类

Groovy类是数据的集合和对该数据进行操作的方法的载体,类的数据和方法用于表示问题域中的一些现实世界对象。Groovy中的类声明了该类定义的对象的状态(数据)和行为。因此,Groovy类描述了该类的实例字段和方法。

下面的示例展示了Groovy类的定义及它的组成:

class Student {
   int StudentID;		//类的成员变量
   String StudentName;	
	
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;		//为成员变量赋值
      st.StudentName = "Joe"     
   } 
}

getter和setter方法

在任何编程语言中,总是使用private关键字隐藏实例成员,通过提供getter和setter方法来相应地设置和获取实例变量的值。例如下面的代码:

class Student {
   private int StudentID;
   private String StudentName;
    
   void setStudentID(int pID) {
      StudentID = pID;
   }
	
   void setStudentName(String pName) {
      StudentName = pName;
   }
	
   int getStudentID() {
      return this.StudentID;
   }
	
   String getStudentName() {
      return this.StudentName;
   }
	
   static void main(String[] args) {
      Student st = new Student();
      st.setStudentID(1);		//通过setter方法设置属性值
      st.setStudentName("Joe");
		
      println(st.getStudentID());	//通过getter方法获取值
      println(st.getStudentName());    
   } 
}

内部类

在这里插入图片描述

内部类定义在另一个类中,外层类可以访问内部类,内部类也可以使用外层类的成员变量,即使是私有的。其它类不能访问内部类。内部类的示例如下:

class Example { 
   static void main(String[] args) { 
      Outer outobj = new Outer(); //定义外层类对象
      outobj.name = "Joe"; 		  //设置属性值
      outobj.callInnerMethod()    //调用外层类方法		
   } 
} 

//外层类
class Outer { 
   String name;
	
   def callInnerMethod() { 
      new Inner().methodA() //外层类调用内部类的方法
   } 

    //内部类
   class Inner {
      def methodA() { 
         println(name); 
      } 
   } 
}   

在上面的例子中我们做了以下工作:

  • 创建一个名为Outer的类,它将是我们的外层类。
  • 在Outer类中定义名为name的字符串。
  • 在我们的外层类中创建一个内部或嵌套类。
  • 在内部类中,我们可以访问在Outer类中定义的名称实例成员。

继承

extends是用于继承类的关键字,我们通过一个示例介绍groovy中如何继承其它类

//定义Example类
class Example {
   static void main(String[] args) {
      Student st = new Student();	//创建Student类的对象
      st.StudentID = 1;				//给它的属性赋值
		
      st.Marks1 = 10;
      st.name = "Joe";			//student类通过继承Person类
								//获得name属性,并设置它的值
      println(st.name);
   }
} 

//定义Person类
class Person {
   public String name;
   public Person() {}  
} 

//定义Student类并继承Person类
class Student extends Person {
   int StudentID
   int Marks1;
	
   //类的构造器,调用父类的构造器创建Student对象 
   public Student() {
      super();
   } 
}   

抽象类

在这里插入图片描述

抽象类表示通用概念,因此它不能被实例化,但可以被继承。抽象类中的抽象方法只有方法的定义而没有方法的实现,它的实现通过继承它的类来完成,定义抽象类通过关键字abstract来声明,抽象方法也是同样的。下面通过一个示例展示定义和使用抽象类:

class Example { 
   static void main(String[] args) { 
      Student st = new Student(); //创建Student类对象
      st.StudentID = 1;			//给它的属性赋值
		
      st.Marks1 = 10; 
      st.name="Joe"; 	//student类通过继承Person类
       					//获得name属性,并设置它的值
		
      println(st.name); 	
      println(st.DisplayMarks()); 	//调用方法
   } 
} 

//定义抽象类Person
abstract class Person { 
   public String name; 
   public Person() { } 
   abstract void DisplayMarks();	//抽象方法的定义
}

//Student类继承抽象类Person
class Student extends Person { 
   int StudentID 
   int Marks1; 
	
   public Student() { 
      super(); 
   } 

    //实现父类中的抽象方法
   void DisplayMarks() { 
      println(Marks1); 
   }  
} 

接口

在这里插入图片描述

接口定义了类需要遵守的规范,接口仅定义需要实现的方法的列表,但是不定义方法实现。接口需要使用interface关键字声明接口,接口的方法总是公开的,在接口中使用受保护或私有方法是一个错误。我们通过下面的示例定义一个接口:

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.Marks1 = 10;
      println(st.DisplayMarks());
   } 
} 

//定义接口Marks
interface Marks { 
   void DisplayMarks(); 	//定义接口中的方法
} 

//定义Student类并实现Marks接口
class Student implements Marks {
   int StudentID
   int Marks1;
	
    //实现Marks接口中的方法
   void DisplayMarks() {
      println(Marks1);
   }
}

在上面的示例中:

  • 创建了一个名为Marks的接口并创建一个名为DisplayMarks的接口方法
  • 在Student类中,使用implements关键字来实现接口
  • 在实现类中必须为接口中DisplayMarks方法提供实现

1. 下列关于类的说法错误的是?

A 类名可以与类中的方法同名

B abstract可以用于声明类或方法

C 子类的构造器可以访问父类的构造器

D 子类可以重写父类的所有方法

2. 下列关于继承说法正确的是?

A 子类继承父类的public方法和属性

B 子类可以继承父类的私有方法和属性

C 子类只继承父类的方法但不继承父类的属性

D 子类继承父类所有的方法和属性

答案

1=>D 2=>A

11 闭包的概念及使用

在这里插入图片描述

Groovy中的闭包完全避免了冗长的代码,而且可以辅助创建轻量级、可复用的代码片段。

通过一个示例来比较传统方式和使用闭包方式的不同

//求1-n中偶数之和
def sum(n){
    total=0
    for(int i=2;i<=n;i+=2){
        total+=i
    }
    total
}
println "sum of even numbers from 1 to 10 is ${sum(10)}"

上述代码运行了一个for循环,在偶数上迭代求和

//求1-n中偶数的乘积
def product(n){
    prod=1
    for(int i=2;i<=n;i+=2){
        prod *=i
    }
    prod
}
println "Prod of even numbers from 1 to 10 is ${product(10)}"

我们在求和代码的基础上修改一下,变成求1到10中偶数的乘积。从中提出任务的共同部分就是for循环,把代码改造如下:

def pickEven(n,block){
    for(int i=2;i<=n;i+=2){
        block(i)	//指向闭包的调用
    }
}
pickEven(10,{println it})	//{}里面是匿名代码块

在for循环中,变量block保存了一个指向闭包的引用,我们可以像传递对象一样传递闭包。变量名可以是任何合法的变量名,我们把这种匿名代码块称为闭包(Closure)。

通过闭包的方式来求1-10中偶数之和,代码如下:

total=0
pickEven(10,{total+=it})
println "sum of even numbers from 1 to 10 is ${total}"

通过闭包的方式来求1-10中偶数的乘积,代码如下:

product=1
pickEven(10,{product*=it})
println "Prod of even numbers from 1 to 10 is ${product}"

Groovy的闭包不能单独存在,必须附着在方法身上,或者赋给一个变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/427012.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java+SpringBoot+Vue自习室预约系统全栈开发

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Windows Docker 部署 SQL Server

部署 SQL Server 打开 Docker Desktop&#xff0c;切换到 Linux 容器。然后在 PowerShell 执行下面命令&#xff0c;即可启动一个 SQL Server 服务。这里安装的是 2022 年版本&#xff0c;如果需要安装其他或者最新版本&#xff0c;可以到 Microsoft Artifact Registry 进行查…

利用redis实现秒杀功能

6、秒杀优化 这个是 图灵 的redis实战里面的一个案例 6.1 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤…

ywtool工具默认功能

提示:工具下载链接在文章最后 目录 一.资源检查二.日志刷新三.工具升级四.linux运维工具ywtool介绍五.ywtool工具下载链接 一.资源检查 只要系统安装了ywtool工具,默认就会配置上"资源检查"的脚本资源检查脚本的执行时间:每天凌晨3点进行检查资源检查脚本的检查内容…

创业者的智选:知识付费小程序定制开发服务解析

探索知识付费领域的新时代&#xff0c;选择专业的知识付费小程序定制开发服务&#xff0c;打造个性化、高效的知识传播平台。无论您是企业、机构还是个体创作者&#xff0c;都能助您成功变现知识资产。 知识付费小程序的开发是一个涉及多方面技术的综合性工程。下面提供一些关…

开发知识点-Vlang

Vlang https://vlang.io/ Vlang 语言是一门新发布的静态类型语言&#xff0c;由 Alexander Medvednikov 发起&#xff0c;开源时间为2019年6月22日1。目前在 GitHub 上已有超过3万颗星&#xff0c;贡献者已有5百多人&#xff0c;快速迭代开发中2。Vlang 语言的设计目标是简单、…

OpenCV 4基础篇| OpenCV图像的拆分和合并

目录 1. 通道拆分1.1 cv2.split1.1.1 语法结构1.1.2 注意事项1.1.3 代码示例 1.2 NumPy切片1.2.1 代码示例 2. 通道合并2.1 cv2.merge2.1.1 语法结构2.1.2 注意事项2.1.3 代码示例 1. 通道拆分 1.1 cv2.split 1.1.1 语法结构 b,g,r cv2.split(img[, mv]) #图像拆分为 BGR 通…

《TCP/IP详解 卷一》第10章 UDP 和 IP 分片

目录 10.1 引言 10.2 UDP 头部 10.3 UDP校验和 10.4 例子 10.5 UDP 和 IPv6 10.6 UDP-Lite 10.7 IP分片 10.7.1 例子&#xff1a;IPV4 UDP分片 10.7.2 重组超时 10.8 采用UDP的路径MTU发现 10.9 IP分片和ARP/ND之间的交互 10.10 最大UDP数据报长度 10.11 UDP服务器…

设计模式(十二)享元模式

请直接看原文: 原文链接:设计模式&#xff08;十二&#xff09;享元模式-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 享元模式定义 享元模式是结构型设计模式的一种&am…

两天学会微服务网关Gateway-Gateway简介

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…

lv20 QT主窗口4

熟悉创建主窗口项目 1 QAction 2 主窗口 菜单栏&#xff1a;fileMenu menuBar()->addMenu(tr("&File")); 工具栏&#xff1a;fileToolBar addToolBar(tr("File")); 浮动窗&#xff1a;QDockWidget *dockWidget new QDockWidget(tr("Dock W…

C语言-简单实现单片机中的malloc示例

概述 在实际项目中&#xff0c;有些单片机资源紧缺&#xff0c;需要mallloc内存&#xff0c;库又没有自带malloc函数时&#xff0c;此时&#xff0c;就需要手动编写&#xff0c;在此做个笔录。&#xff08;已在项目上使用&#xff09;&#xff0c;还可进入对齐管理机制。 直接…

韦东山嵌入式Liunx入门驱动开发五

文章目录 一、驱动程序基石1-1 休眠与唤醒1-2 POLL机制1-3 异步通知(1) 异步通知程序解析(2) 异步通知机制内核代码详解 1-4 阻塞与非阻塞1-5 定时器(1) 内核函数(2) 定时器时间单位 1-6 中断下半部 tasklet 本人学习完韦老师的视频&#xff0c;因此来复习巩固&#xff0c;写以…

2023年第十四届蓝桥杯大赛软件类省赛C/C++大学A组真题

2023年第十四届蓝桥杯大赛软件类省赛C/C大学A组部分真题和题解分享 文章目录 蓝桥杯2023年第十四届省赛真题-平方差思路题解 蓝桥杯2023年第十四届省赛真题-更小的数思路题解 蓝桥杯2023年第十四届省赛真题-颜色平衡树思路题解 蓝桥杯2023年第十四届省赛真题-买瓜思路题解 蓝桥…

c/c++ | 静态链接、动态链接

正如标题所见&#xff0c;我们就来讲讲开发时遇到的一些问题&#xff0c;以及解决方案 这里不介绍动态库、静态库的生成与调用&#xff0c; 无论是静态库还是动态库&#xff0c;都是在编译项目的时候链接器会根据编译命令去调用的 如果直接把库&#xff08;动态、静态不论&…

自己本地模拟内存数据库增删改查

目录 学习初衷准备代码实现结果感谢阅读 学习初衷 用于满足自己的测试要求&#xff0c;不连接数据库&#xff0c;也不在意数据丢失 准备 maven依赖 org.springframework.boot spring-boot-starter-test test 代码实现 内存数据库&#xff08;InMemoryDatabase&#xff0…

玩转SpringBoot:动态排除Starter配置,轻松部署

引言 在软件开发中&#xff0c;进行本地单元测试是一项常规且必要的任务。然而&#xff0c;在进行单元测试时&#xff0c;有时需要启动一些中间件服务&#xff0c;如Kafka、Elasticjob等。举例来说&#xff0c;我曾经遇到过一个问题&#xff1a;项目中使用了Redisson锁&#x…

试手一下CameraX(APP)

书接上回。 首先还是看谷歌的官方文档&#xff1a; https://developer.android.com/media/camera/camerax?hlzh-cn https://developer.android.com/codelabs/camerax-getting-started?hlzh-cn#1 注&#xff1a;这里大部分内容也来自谷歌文档。 官方文档用的是Kotlin&…

JavaWeb之 创建 Web项目,使用Tomcat 部署项目,使用 Maven 构建Web项目(一万八千字详解)

目录 前言3.1 Tomcat 简介3.1.1 什么是 Web服务器3.1.2 Tomcat 是什么3.1.3 小结 3.2 Tomcat 的基本使用3.2.1 下载 Tomcat3.2.2 安装 Tomcat3.2.3 卸载 Tomcat3.2.4 启动 Tomcat3.2.5 关闭 Tomcat3.2.6 配置 Tomcat3.2.7 在 Tomcat 中部署 Web项目 3.3 在 IDEA 中创建 Web 项目…

探索前景:机器学习中常见优化算法的比较分析

目录 一、介绍 二、技术背景 三、相关代码 四、结论 一、介绍 优化算法在机器学习和深度学习中至关重要&#xff0c;可以最小化损失函数&#xff0c;从而改善模型的预测。每个优化器都有其独特的方法来导航损失函数的复杂环境以找到最小值。本文探讨了一些最常见的优化算法&…