Groovy入门(有java基础)

一、基本概念

Groovy是一种基于Java虚拟机(JVM)的动态开发语言,旨在扩展Java语法,提供更简洁、灵活和易于使用的编码方式。
本文是在会一定java语言开发的基础上进行的对比入门学习记录。

1. 特点:

  • 动态性:Groovy支持动态类型和动态元编程,使得代码更加灵活和易于编写。
  • 简洁性:Groovy的语法相对于Java来说更加简洁,可以用更少的代码实现相同的功能。
  • 闭包:Groovy提供了强大的闭包支持,使得函数式编程更为便捷。
def calculator = { operation, a, b ->
    switch (operation) {
        case "+": return a + b
        case "-": return a - b
        case "*": return a * b
        case "/": return a / b
        default: throw new IllegalArgumentException("Unknown operation")
    }
}
println calculator("+", 5, 3)
  • 无缝集成:Groovy可以直接使用Java类和库,与Java代码无缝集成,并且可以通过Java调用Groovy代码。
  • 领域专用语言(DSL):Groovy具有强大的DSL开发能力,允许开发人员根据特定领域的需求创建简洁、可读性高的领域特定语言。

2. 编码风格

与java基本相同,文件后缀为.groovy,示例:

class Datapatch extends BaseModel {

    String patchId
    Date createdAt
    Date updatedAt
    DatapatchDetails details

    @Override
    String getPK() {
        return patchId
    }

    @Override
    void setPK(String pk) {
        patchId = pk
    }
}

3. 环境配置

(1) jdk
(2) groovy sdk

二、语法区别

1. 变量声明

groovy除了可以使用所有java语言的变量声明方式,还可以用def来声明,def声明变量不用指定类型,访问权限默认为public

def s1 = "test"
def i1 = 123
def f1 = 12.1f
def c1 = 'c'

int a = 10

2. 方法

使用 返回类型def关键字 定义,方法可以接收任意数量的参数,这些参数可以不申明类型, 如果不提供可见性修饰符,则该方法为 publicdef也可以用来声明函数。

//def定义方法 不声明返回类型和参数类型
def func1(name) {
    //$占位符插值
    println "$name"
}

//不声明返回类型,声明参数类型
def func2(int i, int b) {
   return i + b
}

//返回类型声明方法,与java相同的方式
int func3(int a){
    return a + 1
}

//可以在方法上指定默认值
def func4(word = "Hello ", name) {
  println word + name
}
//调用的时候就可以不用传这个参数,如果传了就覆盖
func4("groovy")//输出 Hello groovy

//省略分号,类型,return
def func5(a,b,c) {
   a,b,c //最后一行表达式的值会return
}
//省略 方法括号
def number = func5 a,b,c

//命名参数方法,用Map作为唯一参数
def foo(Map args){
    println args.name
}
foo(name:'test',code:1)
与java对比可省略的地方

○ 语句后面的分号
○ 调用方法的括号
○ 参数类型
○ return,方法最后一行的表达式结果默认return
○ 类、属性和方法的访问修饰符,省略默认为pblic,java省略默认是protected

3. 类

与java类似,只不过省略public修饰符
● 默认类的修饰符为public,所有class及方法都是public
● 没有可见性修饰符的字段默认为类的属性,会自动生成对应的settergetter方法。
● 类不需要与它的源文件有相同的名称,但还是建议采用相同的名称。
● 所有类 都继承自 GroovyObject

class Test{
    //会自动对没有访问修饰符(默认是public)生产getter、setter
    String name
    int num

    //创建对象方式四和五 需要声明构造方法
    TestClass(name, age) {
        this.name = name
        this.age = age
    }

    //静态内部类
    static class StaticInnerClass{

    }

    //非静态内部类
    class InnerClass {

    }
}

//创建对象方式一:与java相同
Test test1 = new Test()
test1.name = "测试1"
//创建对象方式二:当一个类没有构造方法的时候,其默认有一个命名参数构造方法
Test test2 = new Test(name:"测试2",num:10)
//创建对象方式三:with是一种特殊的用于减少重复代码的方式
Test test3 = new Test()
test3.with{
    name = "测试3"
    age = 20
}
//创建对象方式四:需要先有构造方法
 def test4 = ["测试4",30] as Test
//创建对象方式五:需要先有构造方法
Test test5 = ["测试5",40]

//创建静态内部类
def staticInner = new StaticInnerClass()

//创建非静态内部类
Test test = new Test()
def inner = new InnerClass(test)

4. for循环

除了支持java的foreach和for i 形式,groovy还支持for in loop形式,支持遍历范围、列表、Map、数组和字符串等多种类型

println "for in loop range"
for ( i in 0..3 ) {
    println i
}
println "for in loop array"
for ( i in [0, 1, 2, 3] ) {
    println i
}
println "for in loop map"
def map = ['a':1, 'b':2, 'c':3]
for ( v in map.values() ) {
    println v
}

5. 数据类型

GString(插值字符串groovy.lang.GStrin)

groovy独有,GString是可变的,GString和String即使有相同的字面量,它们的hashCodes的值也可能不同,因此应该避免使用GString作为Map的key

//通过占位符插值的字符串是可变的,所以这种字符串类型就是GString
String s1 = "123"
GString string = "$s1"
println(string.hashCode())
String s2 = "123"
println(s2.hashCode())
String s3 = "123"
println(s3.hashCode())
//输出 48727 48690 48690

//单引号字符串,原样输出不可变,不支持插值和转义
def s1 = 'Single-quoted strings'
//双引号字符串,支持插值和转义
def ss = "111"
def s1 = "Double-quoted strings $ss"
//三引号字符串,常用于多行文本,支持插值和转义
def s1 = """Triple-quoted strings
            This is second line"""
Groovy中的容器类

List:默认实现类ArrayList,可以直接使用[]声明一个lsit

//定义list
//groovy方式
def list1 = [1,2,3]
def list2 = []
//java方式
def list3 = new ArrayList()

//取值
//java方式
println list1.get(0)
//groovy方式
println list1[-1]
println list1.getAt(-2)

//添加值
list1 << 4
list1.leftShift(5)
list1 += 6
list1.plus 7
//插入指定位置
list1[1] = 21
list1.add(1,'e')
//插入另一个列表所有值
list1.addAll(1,[11,22])
//这种方式第一个值必须是list
list += [1,2] + 12 + 13 +  [11,22]

//删除值
//删除所有值等于1的值
list1 -= 1
list1.remove 1

//遍历
list1.foreach{
  //it是对应当前元素的隐式参数
  println it
}
//带索引遍历
list1.eachWithIndex { it,idx->
  println "value:$it,index:$idx"
}

//过滤使用的一些方法
find/findAll/findIndexOf/indexOf/every/any/groupBy
//常用方法collect,用来转换列表元素
def numbers = [1, 2, 3, 4, 5]
def squaredNumbers = numbers.collect { it * it }
println "Squared numbers: $squaredNumbers"
// 输出 Squared numbers: [1, 4, 9, 16, 25]

Map:直接使用[:]声明,默认的实现类为java.util.LinkedHashMap

def key = 'name' 
//key 就是 "key"
def person = [key: '耗子尾汁'] 
//用括号表示传递一个变量,key='name'
person = [(key): '耗子尾汁']

//生成空map
def m = new HashMap()
def map = [:]

三、闭包

  1. 闭包是一个开放的、匿名的、可以接受参数和返回值并分配给变量。
  2. 也可以看做是一个对象,Closure类型的对象。
  3. 语法就是一段使用花括号{}括起来的代码块,闭包默认存在一个隐式形参it
    def 闭包变量名 = { [形参1, 形参n] -> 闭包体 }
  4. 示例
//只有一个参数或没有参数,形参可以不写
def func1 = {print it}
func1.call("test")

	//多个参数则要显示定义
	def func2 = {name,age ->{ println "name:$name,age:$age"}}
	func2.call("test1",10)
  1. 三个关键变量
    this:代表定义闭包的类。只有一个闭包,并且没有嵌套闭包的情况下,this、owner、delegate指向相同。this不能修改。
    owner:代表闭包定义处的类或者对象。在闭包嵌套闭包中,owner、delegate指向离它们最近的闭包对象。this指向最近的类。owner不能修改。
    delegate:可以代表任意对象,默认情况下owner和delegate是一样的。delegate释义为委托,所以可以手动修改指向其他对象。 delegate可以修改。
  2. 使用场景
    在函数式编程中,将闭包作为参数传递给其他方法

四、trait

Trait具有Java Interface和抽象类的双重特征,介于java的接口和抽象类之间的,主要用来解决多重继承需求,在使用上:
● 可以定义属性,非final类型的,可以修改
● 像java-interface-default方法一样,有具体实现的方法
● 没有具体实现的方法必须用abstract修饰为抽象方法
● 可以使用extendsimplement来继承trait类
● 当不同Trait定义了相同的field或者method时, 将它们同时implements的时候,后面的会覆盖前面的。比如 class A implements B,C ,那么C的field和method会覆盖B的

trait TestInterface {
    String name

    abstract void method1()

    default String method2(){
        name = "cccc"
        return name
    }
}

//实现类
class TestInterfaceImpl implements TestInterface {

    @Override
    void method1() {
        System.out.println(this.method2());
    }

    static void main(String[] args) {
        TestInterface t = new TestInterfaceImpl()
        t.method1()
    }
}

五、元编程

1、概念

元编程是指在运行时创建、修改或操纵程序的能力。在代码执行过程中对程序进行自省和改变,从而实现更高级别的抽象和灵活性。

1.1 优势和用途

动态性:元编程使得在运行时创建、修改或删除类、对象、方法等成为可能。这种动态性使得我们可以根据运行时的情况来改变程序的行为,从而增强了程序的灵活性。
简化重复工作:通过使用元编程,我们可以编写更少的代码来实现相同的功能。通过动态地生成代码、修改代码或使用模板,我们可以避免冗长、重复的代码并提高开发效率。
领域特定语言(DSL):元编程使得创建领域特定语言成为可能。通过定义自己的语法和语义,我们可以为特定领域提供更易于理解和使用的接口。
框架扩展:许多开源框架都使用元编程来实现其内部机制。通过利用元编程能力,我们可以扩展这些框架的功能,满足我们特定的需求。

1.2 流程

简单来说就是运行时期的一个策略。例如调用一个对象的某一个方法,如果这个方法不存在,编译器也不会报错,而是通过一系列的查找最终确定是调用还是抛出异常,下面就是简化后的流程:
Groovy入门(有java基础)_第1张图片

1.3 使用示例

现在有一个类结构如下:

package com.alvin.learn.test

class TestClass {
    String name
    Integer age
}
1.3.1 动态添加属性
//TestClass本来没有code属性,动态添加一个
TestClass.metaClass.code = 10
def test = new TestClass()
println test.code
//可以正常修改
test.code = 2
println test.code

//输出 10 2
1.3.2 动态添加方法
def test = new TestClass()
//1、现在类里面没有testMethod方法,所以执行会报 找不到此方法
test.testMethod("this is args")

//2、在TestClass 里面重写 invokeMethod方法
def invokeMethod(String name,Object args){
    println("调用了invokeMethod,name:$name,args:$args")
}

//3、再次执行1处的调用,会打印
//调用了invokeMethod,name:testMethod,args:[this is args]

//4、在TestClass 里面重写 methodMissing方法
def methodMissing(String name,Object args){
    println("调用了imethodMissing,name:$name,args:$args")
}
//5、再次执行1处的调用,会打印
//调用了imethodMissing,name:testMethod,args:t[this is args]

//6、动态创建方法
TestClass.metaClass.testMethod = {
    println it
}
def test = new TestClass()
test.testMethod("this is args")
//打印 this is args

//7、动态添加静态方法
TestClass.metaClass.static.testStaticMethod = {
    println 'this is a new static method'
}
TestClass.testStaticMethod()
//打印 this is a new static method
1.3.3 全局使用

以上使用都是临时的,在别的类中使用添加的方法需要重新注入,以下使全局使用示例。

class TestManager {
    static TestClass createTest(String name, int age) {
        //调用不存在的方法
        return TestClass.createTest(name, age)
    }
}


class ApplicationManager {
    static void init() {
        //设置全局
        ExpandoMetaClass.enableGlobally()
        //创建 Person 静态方法
        TestClass.metaClass.static.createTest = {
            String name, Integer age ->
                return new TestClass(name: name, age: age)
        }
    }
}


class Main {
    public static void main(String[] args) {
        println '应用程序正在启动'
        //初始化
        ApplicationManager.init()
        println '应用程序初始化完成'

        def test = TestManager.createTest("张三", 20)
        println test.name + "----" + test.age
    }
}
1.3.4 动态创建类
// 创建一个新的类
def myClass = this.class.classLoader.parseClass("""
class MyDynamicClass {
    String name
 
    MyDynamicClass(String name) {
        this.name = name
    }
}
""")
 
// 使用MetaClass为类添加方法
MyDynamicClass.metaClass.sayHello = { ->
    "Hello, my name is ${delegate.name}"
}
 
// 实例化对象并调用新方法
def obj = new MyDynamicClass('Groovy')
println obj.sayHello()

你可能感兴趣的:(groovy,java,开发语言)