当前位置: 首页 > news >正文

【Groovy】函数、闭包、泛型

1 函数

1.1 无参函数

        1)常规调用

void myFun() {
    println("myFun")
}

myFun() // 打印: myFun

        2)字符串声明函数

void "myFun"() {
    println("myFun")
}

myFun() // 打印: myFun

        3)字符串调用函数

void myFun() {
    println("myFun")
}

"myFun"() // 打印: myFun

1.2 有参函数

        1)常规调用

void myFun(Integer num, String str) {
    println("$num, $str")
}

myFun(5, "abc") // 打印: 5, abc

        在不引起歧义的情况下,可以省去小括号,如下。

void myFun(Integer num, String str) {
    println("$num, $str")
}

myFun 5, "abc" // 打印: 5, abc

        2)入参指定默认值

void myFun(String str = "abc") {
    println(str)
}

myFun() // 打印: abc

1.3 有返回值函数

def add(int a, int b) {
    return a + b
}

def c = add(3, 5)
println(c) // 打印: 8

1.4 可变长参数函数

        1)常规调用

void myFun(String... params) {
    for (str in params) {
        println(str)
    }
}

myFun("aa", "bb", "cc") // 打印: aa、bb、cc

        说明:函数的可变长参数个数最多为 1 个。 

        2)使用数组接收可变长参数

void myFun(String... params) {
    String[] arr = params
    println(arr.size())
}

myFun("aa", "bb", "cc") // 打印: 3

        3)将数组传给可变长参数函数

void myFun(String... params) {
    println(params.size())
}

String[] arr = ["aa", "bb", "cc"]
myFun(*arr)  // 打印: 3
myFun("xx", *arr, "yy")  // 打印: 5

2 闭包

        Groovy 中的闭包与 Java 中匿名函数(即没有名字的函数)有些类似,并且也提供了类似 Lambda 表达式的写法(详见 → Java 中 Lambda 表达式总结、Kotlin 中 Lambda 表达式)。

2.1 闭包的创建

2.1.1 通过 new 创建闭包

Closure myFun = new Closure(null) {
    int call(int a, int b) {
        return a + b
    }
}

def res = myFun(3, 5)
println(res) // 打印: 8

2.1.2 通过 {} 创建闭包

        1)无参闭包

def myFun = {
    println("myFun")
}

myFun() // 打印: myFun

        2)有参闭包

def myFun = { String str ->
    println("myFun, $str")
}

myFun("abc") // 打印: myFun, abc

        闭包的入参类型可以省去,如下。

def myFun = { str ->
    println("myFun, $str")
}

myFun("abc") // 打印: myFun, abc

        当闭包入参个数只有一个时,可以省去,引用时使用 it 替代,如下。

def myFun = {
    println("myFun, $it")
}

myFun("abc") // 打印: myFun, abc

        3)有返回值闭包

def myFun = { a, b ->
    return a + b
}

def res = myFun(3, 5)
println(res) // 打印: 8

2.2 闭包对象封装函数

        本节主要介绍使用闭包对象封装一个函数。

2.2.1 使用 {} 封装函数

void test() {
    println("test")
}

def myFun = { test() }
myFun() // 打印: test

2.2.2 使用 this.& 封装函数

        1)无参函数

void test() {
    println("test")
}

def myFun = this.&test
myFun() // 打印: test

        2)有参函数

void test(int a, String b) {
    println("test, $a, $b")
}

def myFun = this.&test
myFun(123, "abc") // 打印: test, 123, abc

        3)有返回值函数

def test(int a, int b) {
    return a + b
}

def myFun = this.&test
def res = myFun(3, 5)
println(res) // 打印: 8

2.3 函数参数是闭包

        1)闭包无参

void outFun(Closure closure) {
    closure()
}

outFun({
    println("inFun") // 打印: inFun
})

         当函数入参的最后一个参数是闭包时,可以将 {} 移到 () 外面(该方式称为尾随 Lambda 表达式);在不引起歧义的情况下,可以省去 (),如下。

void outFun(Closure closure) {
    closure()
}

outFun {
    println("inFun") // 打印: inFun
}

        2)闭包有参

void outFun(Closure closure) {
    closure("abc")
}

outFun { a ->
    println(a) // 打印: abc
}

        当闭包入参个数只有一个时,可以省去,引用时使用 it 替代,如下。

void outFun(Closure closure) {
    closure("abc")
}

outFun {
    println(it) // 打印: abc
}

        3)闭包有返回值

void outFun(Closure closure) {
    def res = closure(3, 5)
    println(res)
}

outFun { a, b ->
    a + b // 打印: 8
}

2.4 通过字符串调用对应函数

void myFun(String str, int num) {
    println("myFun, $str, $num")
}

void test(String funName, String str, int num) {
    def method = this.&"$funName"
    method(str, num)
}

test("myFun", "abc", 3) // 打印: myFun, abc, 3

3 泛型函数

        泛型的类型检查只存在于编译阶段,在源代码编译之后,不会保留任何关于泛型类型的内容,即类型擦除。

3.1 简单泛型函数

        1)单泛型参数

<T> void myFun(T param) {
    println(param)
}

myFun(123)  // 打印: 123
myFun("abc")  // 打印: abc
myFun(true)  // 打印: true
myFun(null)  // 打印: null

        2)多泛型参数

<R, T, S> R myFun(T a, S b, R c) {
    println("$a, $b")
    return c
}

def res = myFun("abc", 123, true) // 打印: abc, 123
println(res) // 打印: true

3.2 类中泛型函数

class MyClass<T> {
    void myFun(T a) {
        println(a)
    }
}

def c1 = new MyClass<String>()
c1.myFun("abc") // 打印: abc
def c2 = new MyClass<Integer>()
c2.myFun(123) // 打印: 123

3.3 抗变、协变和逆变

        Groovy 中不存在 Java 和 Kotlin 中的抗变、协变和逆变现象(详见 → 【Kotlin】函数)。

        如下,Integer 是 Number 的子类,Number 引用可以指向 Integer 对象,并且 Data<Number> 引用可以指向 Data<Integer> 对象,Data<Integer> 引用也可以指向 Data<Number> 对象,还可以访问、修改对象的泛型变量,这在 Java 和 Kotlin 中是不允许的。

class Data<T> {
    T value

    Data(T value) {
        this.value = value
    }
}

Data<Integer> data1 = new Data<Integer>(1)
Data<Number> data2 = data1
data2.value = 10f
println(data2.value) // 打印: 10.0

Data<Number> data3 = new Data<Number>(1.5f)
Data<Integer> data4 = data3
data4.value = 15
println(data4.value) // 打印: 15

3.4 泛型的界

        Groovy 泛型中,可以为其指定上界。

        1)单上界

class Data<T extends Number> {
    T value

    Data(T value) {
        this.value = value
    }
}

Data<Integer> data1 = new Data<Integer>(1)
Data<String> data2 = new Data<String>("abc") // 运行错误, 指定了上界为Number

        2)多上界

class A {}
interface B {}

class C extends A implements B {}

class Data<T extends A & B> {
    T value

    Data(T value) {
        this.value = value
    }
}

def data = new Data(new C())

3.5 运行时检查泛型类型

        Kotlin 中可以通过 inline 和 reified 关键字实现泛型类型检查(详见 → 【Kotlin】函数),它在编译阶段实现。

        Groovy 是动态类型语言,类型检查在运行时进行,可以通过反射来实现类似的功能,如下。

<T> boolean isType(Class<T> type, value) {
    return type.isInstance(value)
}

println(isType(Integer, "abc")) // 打印: false
println(isType(String, "abc"))  // 打印: true
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dtcms.com/a/44723.html

相关文章:

  • SpringBoot项目启动报错:PathVariable annotation was empty on param 0.
  • 20250301在chrome中安装CRX猫抓
  • 计算机视觉|ViT详解:打破视觉与语言界限
  • Ruby 数组(Array)
  • Android中使用Robolectric测试点击事件(不需要手机)
  • 卷积神经网络(Convolutional Neural Network,CNN)详细解释(带示例)
  • MySQL 架构与 SQL 执行全流程解析
  • 数据库基础三(MySQL数据库操作)
  • ubuntu防火墙iptables
  • C大调中的A4=440Hz:音乐、物理与认知的交响
  • kubernetes 部署项目
  • 基于javaweb的SpringBoot在线动漫信息平台系统设计和实现(源码+文档+部署讲解)
  • Hive的内置函数
  • 【算法】图论 —— Floyd算法 python
  • Linux 动静态库和_make_进度条(一)
  • 通俗易懂,什么是cache一致性
  • Leetcode-853. Car Fleet [C++][Java]
  • Autosar RTE配置-Port Update配置及使用-基于ETAS工具
  • P8649 [蓝桥杯 2017 省 B] k 倍区间--前缀和--同余定理【蓝桥杯简单题-必开long long】
  • 基于ssm的校园跑腿管理系统+vue
  • 【练习】【贪心】力扣452. 用最少数量的箭引爆气球
  • Hutool - POI:让 Excel 与 Word 操作变得轻而易举
  • 2024年12月中国电子学会青少年软件编程(图形化)等级考试试卷(二级)答案 + 解析
  • C#上位机--关键字
  • 天锐绿盾软件,如何防止企业内部数据泄露?
  • 高频面试题(含笔试高频算法整理)基本总结回顾29
  • [STM32]从零开始的STM32 BSRR、BRR、ODR寄存器讲解
  • 高频面试题(含笔试高频算法整理)基本总结回顾7
  • IAAS和PAAS层建设CMDB、Hadoop、Doris集群健康度的具体内容有哪些
  • 请谈谈 Node.js 中的流(Stream)模块,如何使用流进行数据处理?