在上一次对于groovy环境进行了搭建并写了一个Helloworld级别的例子感受了一下它的魅力,接下来则来具体学习一下它的语法,要想学得扎实枯燥的语法的坎是必须得过的。
变量:
变量的类型:
- 基本类型:这个跟java差不多,回忆一下:
- 对象类型:也跟Java差不多。
但是!!!在Groovy中基本类型也是对象类型,下面用代码来论证一下:
![](https://i-blog.csdnimg.cn/blog_migrate/2c147d6443432ee0e70f36978d60ca1b.png)
基本类型也可以输出它的class。。看一下结果:
![](https://i-blog.csdnimg.cn/blog_migrate/9bf1873ff45263b3899aa675c7dfbdf8.png)
是不是从这个打印中可以得知,在Groovy中都是对象类型,这个需要注意!!
变量的定义:
这块跟Java就有一些区别了。
- 强类型定义方式:
啥叫强类型定义呢?
也就是在定义变量的时候明确的指定了该变量的类型了,跟我们使用Java风格一样。
- 强类型def定义方式:
其实在很多其它语言中也有类似的写法,像Kotlin、Dart之类的,很明显对于我们声明的变量完全可以通过等号右侧指定的值来推断出来变量的类型:所以其实没必要显示的指定变量的类型,所以groovy就给咱们提供了这种便捷性,使用一个def既可定义任何变量,下面看一下代码:
那对于这两种方式实际场景该怎么选择呢?有以下两个点要素:
1、这个类只供自己来调用,不会被其它模块所调用,推荐使用def方式定义变量,这样我们可以随时的将其转换成其它类型。
2、如果说类中的变量是需要用于其它类来调用的,则建议用强类型定义的方式,因为强类型定义的变量是不可能改变类型的,这样就保证了外界传给我们的值一定是正确的,而如果这个变量定义成了def,那外界传递给你啥类型的值比较合适呢,这样就不确定了,给调用方造成一个困惑。
下面咱们来修改一下def变量的类型看是否能改类型:
![](https://i-blog.csdnimg.cn/blog_migrate/9c6bcfc621d28dac64cccc2d8f9cf4f8.png)
简单理解:用def定义的弱类型的变量其实是一个Object,可以接收任何类型,而强类型定义的则就是具体的类型。
字符串:
![](https://i-blog.csdnimg.cn/blog_migrate/c761804ac9145c735ae8a7f12b6a6df4.png)
关于Groovy的字符串除了包含Java的字符串外,还有自己的一些字符串,叫GString,下面重点来学习一下:
常用的三种定义方式:
一个单引号:
![](https://i-blog.csdnimg.cn/blog_migrate/f7f268afe99b78b38dc4cf96c1f1aaf6.png)
这个是跟Java不同的地方。
三个单引号:
![](https://i-blog.csdnimg.cn/blog_migrate/9b3fc2b96e82bc1cfda594f6b890e9be.png)
那。。既然都是表示的String,它们俩有啥区别么,其实是有区别的,这里主要是从字符串格式化的角度来进行看待,对于单引号的字符串如果想要有像换行符之类的出现则只能通过+字符串拼接的方式来达成,而对于三个引号则不需要了,下面来演示一下:
![](https://i-blog.csdnimg.cn/blog_migrate/2b60b2b170d751affd2880959739bfc5.png)
貌似第一行显示成空行了:
![](https://i-blog.csdnimg.cn/blog_migrate/171a83484cf1c6fac4a73d298e84026f.png)
那如果想第一行不输出空行,而是从这个地方开始输出呢?
![](https://i-blog.csdnimg.cn/blog_migrate/78b88e2c40b89e7884dbaca2bf21f5cb.png)
这里需要这样做:
![](https://i-blog.csdnimg.cn/blog_migrate/235573134da3db3327851bc10f67a03e.png)
双引号:
这个是在Java中字符串的定义方式,在Groovy中当然也支持:
![](https://i-blog.csdnimg.cn/blog_migrate/9f3c73487ae52f49504140a97cdff463.png)
那。。它又有啥特点么?其实它是一种可扩展的字符串,啥叫“可扩展的字符串”呢?其实就是里面可以有变量,看下面:
![](https://i-blog.csdnimg.cn/blog_migrate/ffd481b62cfb3a5b3fc8e175bcd24561.png)
继续再来看一个扩展的例子:
![](https://i-blog.csdnimg.cn/blog_migrate/fdad10ce1373a14b40af76be11e92e7f.png)
那。。难道单引号里面就不能用这种扩展方式么,试一下就知道了:
![](https://i-blog.csdnimg.cn/blog_migrate/eafafce5b91a2b85d707e02f9673f187.png)
那,既然在Groovy中字符串一个是String,一个是GString,那它们之间互转是怎么搞的呢?下面来看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/d4ce7b022a90732c20e0d08c26c20160.png)
字符串方法:
在Groovy中的String像Java一样定义了很多的API供使用,其中还有Groovy自己扩展的,下面看一下整个Groovy中String API的分类:
![](https://i-blog.csdnimg.cn/blog_migrate/869b01465e1ee7f2be6021de0acff7a5.png)
而闭包类型的api放到之后再来学习,所以这里集中来学习一下常见的普通类型的API:
字符串填充API:
center():
![](https://i-blog.csdnimg.cn/blog_migrate/e065fdd4c720e1ab10f42664254eba01.png)
当然也可以不指定第二个参数,默认则以空格进行填充了:
![](https://i-blog.csdnimg.cn/blog_migrate/a67bfb53301267a4767a1e3ca203f0d5.png)
padLeft()、padRight():
这个就比较好理解了,直接看例子:
![](https://i-blog.csdnimg.cn/blog_migrate/afaf23f8041adb1972d3f7922ffa14dc.png)
比较方法:
![](https://i-blog.csdnimg.cn/blog_migrate/0b746bebcf30f69847a247e4642d260c.png)
字符串索引:
![](https://i-blog.csdnimg.cn/blog_migrate/dbc2c64e2fc4addb8714492d1a8718be.png)
另外下标还可以传入下标,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/2442d269cc68e7c2ed4cd66f65e8c742.png)
minus():
![](https://i-blog.csdnimg.cn/blog_migrate/30e7c457998f14ebd149daf19958995f.png)
其中也可以用操作符来实现同步的效果:
![](https://i-blog.csdnimg.cn/blog_migrate/751b6f82fd998d96d873346768043011.png)
reverse():字符串倒序
![](https://i-blog.csdnimg.cn/blog_migrate/a4b484a8ca0b1b8637c695c694aca917.png)
capitalize():首字母转大写
![](https://i-blog.csdnimg.cn/blog_migrate/ca8cdc7f8c0702e0d562949dae83d214.png)
isNumber():判断是否是数字
![](https://i-blog.csdnimg.cn/blog_migrate/21bf7f6a49fb173413b8f8010efceff0.png)
转换成类型:
这块就不演示了,比较简单:
![](https://i-blog.csdnimg.cn/blog_migrate/fc317fbe45d810bae090da9a08c32992.png)
逻辑控制:
这块比较简单,学一下Groovy跟Java不同的既可:
swich..case..
我们知道在Java中的swich只能是int类型、char类型、String类型、枚举类型的变量,而在Groovy中就没这些限制了,可以传任何类型,下面来看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/0a27cf8a55156c2e373ad8d48411b128.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2922718dbf41a1f911c5ea2598cc4725.png)
再来修改一下让其可以匹配一个数组:
![](https://i-blog.csdnimg.cn/blog_migrate/d7e1f8ef997d7610b649d09b346ca561.png)
所以在groovy代码编写中,如果if..else能用switch..case来代替就尽量用switch..case,因为可读性比较强。
范围的for循环:
![](https://i-blog.csdnimg.cn/blog_migrate/9179b408df0ee25ef62918bb5e3a8b4f.png)
接下来看一下对于数组的循环,基本类似:
![](https://i-blog.csdnimg.cn/blog_migrate/8aa6e7e94a6ce431efc32c660e403892.png)
再看一下对于map的循环:
![](https://i-blog.csdnimg.cn/blog_migrate/22eedbd1665be9031f4149e358ad45bb.png)
闭包:
基础:
关于闭包在其它语言中都有,像Kotlin、Dart等,而闭包在Groovy中又是一个非常重要的概念,所以有必要扎实的去掌握它。
闭包概念:
闭包的定义:
首先先来看一下如何定义一个闭包:
![](https://i-blog.csdnimg.cn/blog_migrate/129443f959b284cdd9fdba72b2790e10.png)
闭包的调用:
那对于闭包代码怎么来执行呢?当然需要有调用才行,如下调用既可:
![](https://i-blog.csdnimg.cn/blog_migrate/b838cdf2db06cd9dde271ba31f372566.png)
闭包参数:
普通参数:
在上面也提到了跟方法很类似,我们知道方法都可以有参数,那。。闭包能有么?当然,具体如何写呢?看下面:
![](https://i-blog.csdnimg.cn/blog_migrate/581e45c330773d13836ab1747cf31d77.png)
不过上面代码有个坑,不知能不能看出来:
![](https://i-blog.csdnimg.cn/blog_migrate/2de8719b691169982a85fcfac690cbf1.png)
这里不过多解释了,改成双引号完事:
![](https://i-blog.csdnimg.cn/blog_migrate/2e337b7237c40093cfb897379146131e.png)
也可以传一个变量:
![](https://i-blog.csdnimg.cn/blog_migrate/585d7b174f9f258c16e8d88e8772e851.png)
那如果有多个参数呢?
![](https://i-blog.csdnimg.cn/blog_migrate/fd75d8801e4a2fc68da5ef7b6d0b0408.png)
隐式参数:
在Groovy中有个语法糖,其实像Kotlin等都有类似的,看一下:
![](https://i-blog.csdnimg.cn/blog_migrate/e7f6f8772c0ca8d540a0f41c8f1d2a33.png)
那如果不想要这个默认参数,那你显示的指定一个参数既可。
闭包返回值:
看一下程序:
![](https://i-blog.csdnimg.cn/blog_migrate/7bb4e51b02614dc9ab99f80f18bb7d73.png)
这个比较好理解,接下来再来变一下:
![](https://i-blog.csdnimg.cn/blog_migrate/7d1fcc1db7f482bbbc00f30353944ec8.png)
基本数据类型与闭包使用:
对于闭包的概念其实比较简单,但是!!它的使用是非常之灵活的,下面看一下在Groovy中闭包的有如下使用场景:
- 与基本类型的结合使用
- 与String的结合使用
- 与数据结构结合使用【这个在未来学习到数据结构时再来看】
- 与文件等结合使用【这个在未来学习到文件时再来看】
求阶乘:
下面先来看一下与基本类型的结合使用,这里来利用闭包的方式来求一个数的阶乘:
![](https://i-blog.csdnimg.cn/blog_migrate/3feff5f89f3ed9562cc6113765835601.png)
看一下upto的参数定义:
![](https://i-blog.csdnimg.cn/blog_migrate/77e7ea975665c109a42e338a2d77cb2d.png)
很明显求阶乘需要有一个循环的,但是我们调用一个API就达到了阶乘的效果,很显然upto里面做工作了,瞅一下它的实现细节:
![](https://i-blog.csdnimg.cn/blog_migrate/d9f7c8ab0f25b68555a74ccd7950dd55.png)
既然有upto,肯定有downto:
![](https://i-blog.csdnimg.cn/blog_migrate/1ea87041e0c086834b5ed204ea56e2b4.png)
所以,咱们也可以用它来实现同样的功能:
![](https://i-blog.csdnimg.cn/blog_migrate/984422966261cdaff641c126a5edaf9b.png)
累加:
![](https://i-blog.csdnimg.cn/blog_migrate/ca9727bba5f9111014fadf65e533ce48.png)
其中有一个写法其实在kotlin中大量运用到:
![](https://i-blog.csdnimg.cn/blog_migrate/c5bb040233767b0d72d4adfdab88cd5e.png)
在Koltin中这样使用是当参数只有一个Lambda表达式则可以直接用花括号打开,而这个times只接收一个闭包,闭包跟Lambda的意义真的差不多,所以也能这样写。下面来瞅一下它的实现:
![](https://i-blog.csdnimg.cn/blog_migrate/68acb8027c720b90f864d730da554192.png)
字符串与闭包结合使用:
接下来再来看一下字符串跟闭包的结合使用,直接看代码
each的遍历:
![](https://i-blog.csdnimg.cn/blog_migrate/e62eca5604f3caa8ecc0a6b0940eac5a.png)
其中看一下each的定义:
![](https://i-blog.csdnimg.cn/blog_migrate/f1ef5567a37134a09eb8bbb737b5d137.png)
![](https://i-blog.csdnimg.cn/blog_migrate/064c8df857808552f27a21e927e0ce71.png)
其中返回的是self,其实也就是字符串本身,咱们来打印一下返回值:
![](https://i-blog.csdnimg.cn/blog_migrate/d152d67b46618ed437641ebcf3a6e708.png)
find:查找符合条件的第一个字符
![](https://i-blog.csdnimg.cn/blog_migrate/c2c5424f55fae32abe3325e5b1179551.png)
findAll:找到所有符合条件的字符:
![](https://i-blog.csdnimg.cn/blog_migrate/2e086890771d07644d44d9e61ed3aa8d.png)
any:根据闭包的条件来返回true或false
![](https://i-blog.csdnimg.cn/blog_migrate/77bb0f1146464f72f179ded0d8d1288c.png)
看一下它的定义:
![](https://i-blog.csdnimg.cn/blog_migrate/68cfe63af2875414eaa5b6f70a71a155.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2306171bec2aace76c262b238f66ff76.png)
every:每一个字符都要满足条件最终才会返回true
![](https://i-blog.csdnimg.cn/blog_migrate/9aa2564b62e48c43bc66a1408c46ef33.png)
collect:根据闭包的行为最终再产生一个集合
![](https://i-blog.csdnimg.cn/blog_migrate/37ea0f37fe201333ca7eda55638c49e1.png)
以上是一些常见的用法,都需要在实际练习中去熟悉。
进阶:
接下来则要展现一下Groovy的闭包跟其它闭包或Java的Lambda表达式的强大处理,不过也稍加难理解一点,下面走起。
闭包关键变量:
Groovy自带的有如下三个关键字:
- this
- owner
- delegate
完全不知道上面有啥用,下面先来在闭包中输出一下,看都是啥?
![](https://i-blog.csdnimg.cn/blog_migrate/b079150d06e631ad595c4884ae5e44cb.png)
居然这三者输出的对象是一模一样的呀,那。。学了有啥意义?其实它们是有区别的,具体有啥区别下面继续来往下探究,先来理解一下这三个关键字所代表的含义:
- this:代表闭包定义处的类
- owner:代表闭包定义处的类或对象
从这个文字描述就能感觉到跟this的不同,它还能代表对象,啥意思,因为闭包里面还可以再定义闭包,所以它也对代表当前闭包对象而非只是定义类,关于这个下面会有例子,先了解一下概念。 - delegate:它代表任意对象,默认与owner一致
下面则来定义多个闭包进一步来看它们的区别:
![](https://i-blog.csdnimg.cn/blog_migrate/1181c2fcffbd1172bfa47e1a722e0dc4.png)
接下来则来调用一下:
![](https://i-blog.csdnimg.cn/blog_migrate/e06b4db00a07255ba6376332aac93525.png)
也就是说闭包的这三个变量永远是看最近定义的类,像这个程序很明显还有一个外部的类:
![](https://i-blog.csdnimg.cn/blog_migrate/346c1a25ec3f4db9539adc140e19073a.png)
其实主要是来看一下在里面又定义了一个闭包的输出,发现输出还是一样。。
![](https://i-blog.csdnimg.cn/blog_migrate/86fa636d7335e2b839b570657aef994a.png)
因为这个闭包中木有定义新的闭包,所以暂时还木有看到this跟owner的区别,在继续来写程序之前,这里将static换成实例方法再来看一下输出:
![](https://i-blog.csdnimg.cn/blog_migrate/3e8430dfcad187e52bf003fadf52d699.png)
好,接一下来咱们在闭包中再定义一个闭包,来看一下this和owner的区别:
![](https://i-blog.csdnimg.cn/blog_migrate/a666dae2865db97d5de95a00181512f3.png)
现在已经知道了this跟onwer的区别了,那。。onwer跟delegate呢?其实默认确实是没区别,但是!!闭包是可以设置委托的,如果设置了之后则就能知道有啥不一样了,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6b6cbc7cf8d752d5ec332fe5758383ac.png)
闭包委托策略:
那搞清了上面三个闭包的变量有啥用呢?它们就可以用到闭包的委托策略中,如何用,下面直接看代码:
![](https://i-blog.csdnimg.cn/blog_migrate/db70a682cfa7baff4a15bc1cb6848559.png)
那有没有办法来将name输出成teacher的呢?当然有,直接修改Student的代码嘛,但是有没有一种不通过修改目前的代码也能达到同样的效果呢?有!!!使用闭包的委托策略,具体看下面:
![](https://i-blog.csdnimg.cn/blog_migrate/3331d3ba2450bd0e03aa164fc3b34cf6.png)
这是因为需要设置一下委托策略,如何设置?
![](https://i-blog.csdnimg.cn/blog_migrate/e9cf0d432e67fda856a20e9e2ab8179c.png)
那如果Teacher类中木有name变量呢?
![](https://i-blog.csdnimg.cn/blog_migrate/c8ee2c65f98c614cd1ebbbbc003ca32d.png)
而如果我们将委托策略变成这个呢?
![](https://i-blog.csdnimg.cn/blog_migrate/d51fc93299b4f020f01734cfdde28b46.png)
从词面意思是只会从委托对象中来找,很明显此时找不到,那应该抛异常,试试:
![](https://i-blog.csdnimg.cn/blog_migrate/9f59b0bba504a7a141527478facf60ba.png)
这里看一下总共有几个委托策略:
![](https://i-blog.csdnimg.cn/blog_migrate/09b01536548382e23af9d0957804bfe1.png)
其实实际中用到这种委托策略的不多,只有写框架的可能会用到,做个了解既可。