Groovy基础

引言:

        Groovy 是一种基于 Java 平台的动态编程语言(指在运行时进行类型检查的语言。在使用动态语言编写程序时,变量的类型不需要在声明时明确指定,而是在运行时根据赋给变量的值来确定类型。动态语言在代码执行过程中会进行类型检查)。它旨在简化和增强 Java 开发,提供了更简洁的语法、闭包、动态类型等特性。Groovy 可以无缝地与 Java 代码互操作,并且可以直接使用 Java 库。下面我们来学习一下Groovy的基础

        注:需要有一定的java基础哦


Groovy开发环境配置

  1. 安装Intellij IEDA开发工具:Download IntelliJ IDEA – The Leading Java and Kotlin IDE
  2. 下载Groovy SDK开发工具:The Apache Groovy programming language - Download
  3. 将Groovy SDK开发工具下的bin文件配置到环境变量中,eg:D:\apache-groovy-sdk-4.0.24\groovy-4.0.24\bin
  4. 检查是否安装成功:groovy -version

学一门语言,第一步该干什么?

  1. 那就是HelloWorld!了
  2. Groovy中可以直接使用java库,也可以直接写java语法
  3. 例如:
    HelloWorld.groovy
    
    class HelloWorld{
        public static void main(String[] args){
            System.out.println("Hello World!");
        }
    }
  4. 在Groovy中可以直接调用方法不用写类、main方法
  5. 最终版本:
    System.out.println("Hello World!")
    或
    println("Hello World!")
    或
    println "Hello World!"

变量

  1. java是一种强类型语言,Groovy既是强类型语言,也是弱类型语言
    1. 强类型:在定义变量时,必须声明其类型,并且后续不能更改其类型
    2. 弱类型:在定义变量时,无需声明其类型,会自动推断出其类型,并且可以修改
  2. Groovy中使用def来定义弱类型变量,也可以省略def
    在java中:
    int a = 1;
    a = "abc"; //编译错误,类型不匹配
    
    在Groovy中:
    使用java的肯定是不行的
    int a = 1;
    a = "abc";//编译错误,类型不匹配
    
    使用def
    def a = 2
    a = "groovy"
    
    省略def
    a = 2
    a = "groovy"
  3. Groovy中的基本数据类型都是以对象的形式存在的,万物皆对象
  4. 证明:
    int x=1
    double y=3.14
    char ch='a'
    boolean flag=true;
    
    println x.class  //class java.lang.Integer
    println y.class  //class java.lang.Double
    println ch.class //class java.lang.Character
    println flag.class //class java.lang.Boolean
    
    
    def x=1
    def y=3.14D
    def ch='a'
    def flag=true
    
    println x.class //class java.lang.Integer
    println y.class //class java.lang.Double
    println ch.class //class java.lang.String
    println flag.class //class java.lang.Boolean
  5. 尽量使用def来定义弱类型变量,因为直接使用x = 1更像赋值操作

字符串

  1. 在 Groovy 中,字符串可以使用单引号、双引号和三引号来表示
  2. 证明:
    def s1='groovy'
    def s2="groovy"
    def s3='''groovy'''
    println s1.class  //class java.lang.String
    println s2.class //class java.lang.String
    println s3.class //class java.lang.String
  3. 有什么区别呢?
  4. 单引号:用于定义普通的字符串,不支持插值,即不支持在字符串中嵌入变量或表达式,就相当于java的“ ”字符串
  5. 双引号:用于定义支持插值的字符串,可以在字符串中嵌入变量或表达式,使用 ${} 语法。
  6. 三引号:用于定义多行字符串,支持插值。它允许字符串跨越多行,且保持格式
    def name = 'Groovy'
    def message1 = 'Hello, ${name}!'  // 单引号不支持插值
    println message1  // 输出 Hello, ${name}!
    
    def message2 = "Hello, ${name}!"
    println message2  //输出 Hello, Groovy!
    
    ========================================================
    实现下面这种效果:
    Hello, Groovy!
    Welcome to the world of Groovy.
    
    单引号:
    def nam1 = 'Groovy'
    def name2 = 'Hello,'+nam1+'\nWelcome to the world of Groovy.'
    
    双引号:
    def name = 'Groovy'
    def message = "Hello,${name}\nWelcome to the world of Groovy."
    println message
    
    三引号:输出多行字符串,保持格式
    def name = 'Groovy'
    def message = """
    Hello, ${name}!
    Welcome to the world of Groovy.
    """
    
    输出结果:
    Hello, Groovy!
    Welcome to the world of Groovy.
  7. 从例子中可以看出,三引号很灵活吧,我们需要换行时,不需要使用\n

闭包Closure

  1. 在Groovy中,闭包是一种类似于匿名函数的概念,就是一个使用花括号包围的代码块,它可以被赋值给变量或作为参数传递给其他函数,闭包的类型为Closure
  2. 基本语法:{参数列表 -> 代码块} ,其中如果没有参数时,(参数列表 ->) 可省略
  3. 无参数闭包、带参数闭包:
    //无参数的闭包
    def closure1={
        println "hello groovy!"
    }
    //使用
    closure1()
    
    
    //带参数的闭包
    def closure2={String name,int age->
        println "hello ${name}:age ${age}"
    }
    //使用
    closure2("wjb",18)
  4. 如果闭包只有一个参数,可以使用隐式参数 it,而不需要显式声明参数。

    def greet = {
        println "Hello, ${it}!"
    }
    
    greet("Groovy")  // 输出 Hello, Groovy!
  5. 闭包的返回值:
    def closure={
        println "hello ${it}"
        return "123" //可以省略return
    }
    def result=closure("groovy")
    println "result="+result
  6. 闭包的类型是Closure,Closure实现了Runnable、Callable接口,Closure实现了call方法和run方法
    public abstract class Closure<V> extends GroovyObjectSupport implements Cloneable, Runnable, GroovyCallable<V>, Serializable {}
  7. 我们可以使用call、run方法来调用我们的闭包
    def closure1={
        println "hello groovy!"
    }
    closure1.run()  //hello groovy!
    closure1.call() //hello groovy!
  8. 为什么呢?
  9. 我们先来看看run方法内部干了什么:

  10. 可以看到run方法调用了call方法
  11. 所以我们来看看call方法干了什么

  12. 可以看到call方法调用了传递任意数量的参数的call方法,最后找到当前的方法doCall,并调用
  13. 难道是Closure的docall方法?不对,因为Closure内部的docall方法最终还是调用了传递任意数量的参数的call方法,那是不是我们定义的闭包中有docall方法呢?我们来看看class文件(Groovy也是在JVM上运行的,也就是说,Groovy代码会编译成字节码,然后在JVM上执行)

  14. 可以看到,我们写了一小段代码,但是class文件有很多内容,这都是Groovy编译器帮我完成的,编译器会自动帮你创建一个和文件名同名的类,把你的代码放入run方法,并在main方法中调用run
  15. 从class文件中可以看到_run_closure1继承了Closure类,所以call方法中,会调用到_run_closure1的docall方法
  16. 闭包可以作为方法的参数传递
  17. 大家可以想一下下面这段代码,是java语法还是Groovy语法呢?
    int x=fab(5)
    int fab(int number){
        int result=1;
        1.upto(number,{num -> result *= num})
        return result
    }
    println x;
  18. 当然是Groovy了,因为方法内有闭包,闭包是Groovy的语法,我们要记住Groovy 可以无缝地与 Java 代码互操作,并且可以直接使用 Java 库,并且可以直接使用java的语法
  19. 这个代码中我们调用了int的api upto(用来迭代从当前数字到目标数字,类似于 Java 中的 for 循环,但更加简洁和直观。)
  20. upto方法的参数需要传递一个Closure

  21. 也可以先定义closure再传入,但是不能在fab方法外部定义,必须定义在fab方法作用域之内
    int fab(int number) {
        int result = 1
        def closure = { num -> result *= num } 
        1.upto(number, closure)
        return result
    }
  22. 当方法的最后一个参数是Closure时,可以将闭包放在方法调用的括号之外
    int fab(int number) {
        int result = 1
        1.upto(number){ num -> result *= num }
        return result
    }
  23. 闭包中有三个关键变量:this、owner、delegate,这些变量在闭包中用来引用不同的上下文对象
  24. 从源码中可以看出owner、delegate是Closure类的两个成员变量,并且是在构造方法中进行赋值的

  25. this 变量指向定义闭包的类(即包含闭包的类)。
    1. 代码:
      class A{
          class B{
              void run(){
                  def closure = {
                      println "run:"+this //run:org.example.study_1.closure.A$B@3b74ac8
                  }
                  closure()
              }
          }
      
          void print(){
              new B().run()
              def closure = {
                  println "print:"+this //print:org.example.study_1.closure.A@7d286fb6
              }
              closure()
          }
      }
      
      new A().print()
    2. 代码解释:run方法的closure闭包是定义在B类中的,所以this指向的是B的实例;print方法的closure闭包是定义在A类中的,所以this指向的是A的实例
    3. 证明:看看对应的class文件
      1. 我们先看看A类的print方法,可以看到我们定义一个闭包,groovy编译器会为我们创建一个Closure对象,那在java中Object closure = new _print_closure1(this, this);的this是指什么?是不是指向当前这个对象--》A的实例,所以print方法的closure闭包的this指向的是A的实例,那么owner、delegate的值是不是和this相同,是相同的,大家可以测试一下

      2. 我们再来看看B类的run方法,原理是不是和上面的一样?对的

    4. 总结:this指向的是闭包外第一个类的实例
  26. owner 变量指向定义闭包的对象,可能是类或闭包。
    1. 代码:
      class Example {
          void run() {
              def nestedClosure = {
                  def innerClosure = {
                      println "innerClosure owner: " + owner  //org.example.study_1.closure.Example$_run_closure1@6aa61224
                  }
                  innerClosure()
                  println "nestedClosure owner: " + owner //org.example.study_1.closure.Example@30c8681
              }
              nestedClosure()
          }
      }
      
      new Example().run()  
    2. 代码解释:owner 变量指向定义闭包的对象,先看看innerClosure闭包的owner,innerClosure闭包是定义在nestedClosure闭包内的,那么owner和nestedClosure指向同一个类的实例;那nestedClosure闭包的owner呢?它是定义在Example类内的,所以owner指向的是Example的实例
    3. 证明:看看对应的class文件
      1. 我们先看innerClosure闭包,Groovy编译器帮我们创建了对象,在java中,Object innerClosure = new _closure2(this, this.getThisObject());的this指的是哪个类的实例?是_run_closure1这个类吧;我们再来看看nestedClosure闭包,在java中,Object nestedClosure = new _run_closure1(this, this);的this指的是哪个类的实例?是Example这个类吧。

    4. 总结:如果闭包定义在类中,则owner指向的是类的实例;如果闭包外还是闭包,则owner指向的是外层闭包的实例对象
  27. delegate 变量指向代理(任意)对象,默认情况下与 owner 相同,但可以被显式更改。
    1. 代码1:默认情况下,delegate 和owner相同
      class Example {
          void run() {
              def nestedClosure = {
                  def innerClosure = {
                      println "innerClosure owner: " + owner  //org.example.study_1.closure.Example$_run_closure1@6aa61224
                      println "innerClosure delegate: " + delegate  //org.example.study_1.closure.Example$_run_closure1@6aa61224
                  }
                  innerClosure()
                  println "nestedClosure owner: " + owner //org.example.study_1.closure.Example@30c8681
                  println "nestedClosure delegate: " + delegate //org.example.study_1.closure.Example@30c8681
              }
              nestedClosure()
          }
      }
      
      new Example().run()
    2. 代码解释:默认情况下,owner和delegate是相同的
    3. 证明:从构造方法中可以看出,owner直接赋值给了delegate

    4. 代码2:修改delegate
      //修改默认的delegate对象
      class Person {
      }
      Person p=new Person();
      def nestClouser = {
          def innerClouser = {
              println "innerClouser:" + this  //org.example.study_1.closure.ClosureTest4@6cb6decd
              println "innerClouser:" + owner //org.example.study_1.closure.ClosureTest4$_run_closure1@40317ba2
              println "innerClouser:" + delegate //org.example.study_1.closure.Person@3c01cfa1
          }
          innerClouser.setDelegate(p) //修改delegate
          innerClouser.call()
      }
      nestClouser.call()
    5. 代码解释:修改delegate的指向为Person
    6. 证明:Closure只提供了setDelegate方法,并没有提供setOwner方法

    7. 总结:在默认情况下delegate是等于owner的,delegate可以被修改
  28. 闭包的委托策略:闭包的委托策略决定了闭包在查找属性和方法时的优先级。Groovy 提供了几种不同的委托策略,可以通过 resolveStrategy 属性来设置
  29. 委托策略,默认策略是Closure.OWNER_FIRST
    1. Closure.OWNER_FIRST,优先级:owner > delegate,闭包首先在其owner上查找属性和方法,如果找不到,则在delegate上查找

    2. Closure.DELEGATE_FIRST,优先级:delegate > owner,闭包首先在其delegate上查找属性和方法,如果找不到,则在owner上查找

    3. Closure.OWNER_ONLY,闭包仅在其owner上查找属性和方法,忽略delegate

    4. Closure.DELEGATE_ONLY,闭包仅在其delegate上查找属性和方法,忽略owner

    5. Closure.TO_SELF,闭包仅在其自身上查找属性和方法,忽略owner和delegate

  30. 代码:
    class Student{
        String name
        def pretty={"My name is ${name}"}
        String toString(){
            pretty.call()
        }
    }
    def student=new Student(name: "groovy") //Groovy编译器会帮我们自动添加一个构造方法
    
    class Teacher{
        String name
    }
    def teacher=new Teacher(name:'andy')
    
    println 'pretty: '+student.toString() // My name is groovy
    println 'delegate: '+student.pretty.delegate  //delegate: com.example.Student@<hashcode>
    
    student.pretty.delegate=teacher
    println 'delegate: '+student.pretty.delegate //org.example.study_1.closure.Teacher@563e4951
    //闭包的委托策略
    student.pretty.resolveStrategy=Closure.DELEGATE_FIRST
    
    println 'pretty: '+student.toString() //pretty: My name is andy
  31. 代码解释:我们这里使用的是Closure.DELEGATE_FIRST策略,那么它就会先从delegate中查找属性和方法

Gradle中常用的数据结构

  1. List:
    1. 定义:
      //使用ArrayList
      def list=new ArrayList()
      
      //使用Groovy
      def list=[1,2,3,4,5]
      println list.class //class java.util.ArrayList
    2. 常用方法:

      //list大小
      println list.size()
      
      ===========添加元素===========
      //使用add方法添加元素
      list.add(6)
      //使用groovy的<<添加元素
      list<<2 
      //也可以使用+添加元素
      def plusList=list+5
      //指定下标,添加元素
      plusList.add(3,9)
      
      ===========删除元素===========
      //删除下标位置的元素
      list.remove(2) 
      //删除指定的元素
      list.removeElement(2)
      //删除符合条件的元素
      list.removeAll{
          return it%2!=0
      }
      //使用-删除元素
      println list-[2,3,4] //将所有数值为2,3,4的全部remove
      
      
      ===========查找元素===========
      //查找满足条件的第一个数据
      int result=findList.find{
          return it%2 == 0
      }
      //查找所有满足条件的数据
      def result2=findList.findAll({
          return it%2 !=0
      })
      //查找是否有满足条件的数据
      def result3=findList.any{
          return it%2 ==0
      }
      //查找是否全部满足条件
      def result4=findList.every{
          return it%2 ==0
      }
      //查找最大值与最小值
      def result5=findList.min{
          return it
      }
      def result6=findList.max{
          return it
      }
      //统计满足条件的元素个数
      int result7=findList.count{
          return it>0
      }
      
      ===========排序元素===========
      //升序
      sortList.sort()
      //降序
      sortList.reverse()
      //根据条件排序
      sortList2.sort{
          it.length()
      }
      
      ===========遍历元素===========
      def list=[1,2,3,4,5]
      //传统的for循环
      //for-in循环
      for (element in list) {
          println element
      }
      //each方法
      list.each { element ->
          println element
      }
      //eachWithIndex方法
      list.eachWithIndex { element, index ->
          println "Index $index, Value $element"
      }
      //iterator方法
      def iterator = list.iterator()
      while (iterator.hasNext()) {
          println "Iterator: ${iterator.next()}"
      }
      
  2. Map
    1. 定义:
      //使用java
      def map = new HashMap<String,Integer>()
      
      //使用Groovy
      //定义一个<Integer,String>
      def map = [1:"one",2:"two"]
      println map.getClass() //class java.util.LinkedHashMap
      //定义一个<String,String>
      def colors=[red:'ff0000',green:'00ff00',blue:'0000ff'] //会将red转换成String
      //可以强转为HashMap
      def colors=[red:'ff0000',green:'00ff00',blue:'0000ff'] as HashMap
    2. 常用方法:
      def colors=[red:'ff0000',green:'00ff00',blue:'0000ff']
      
      //使用key获取value 
      println colors['red'] 或 println colors.red
      
      
      ===========添加元素===========
      //使用put方法
      //使用.
      colors.yellow='ffff00'
      //往map中再添加一个map
      colors.map = [key1:1,key2:2]
      
      ===========移除元素===========
      //使用remove方法
      colors.remove(key)
      
      ===========遍历元素===========
      //使用each
      teachers.each { key, value ->
          println "key=${key}---value=${value}"
      }
      //带索引
      teachers.eachWithIndex{ def key,def value,int index->
          println "index=${index}---key=${key}---value=${value}"
      }
      
      
      ===========查找元素===========
      //查询符合条件的元素
      def entry=teachers.find{def teacher ->
          return teacher.value.name=='groovy'
      }
      //查询符合条件的所有元素
      def entry=teachers.findAll{def teacher ->
          return teacher.value.name=='groovy'
      }
      //查找符合条件的元素个数
      def count=teachers.count{def teacher ->
          return teacher.value.name=='groovy'
      }
      
      ===========排序元素===========
      //注意:map会返回一个新的map   list是在原来的list中进行排序
      def sort=teachers.sort{def t1,def t2 ->
          return t1.key > t2.key ? 1 : -1
      }
      
  3. Range
    1. 在 Groovy 中,Range 是一个非常实用和灵活的特性,可以用来表示一系列连续的值。这些值可以是数字、字符等。
    2. 定义:
      //数字范围
      def numberRange = 1..5
      
      //字符范围
      def charRange = 'a'..'e'
      
    3. 常用方法:
      def range=1..10
      //获取指定下标的元素
      println range[0]
      //是否包含某元素
      println range.contains(8)
      //使用in
      println 3 in range
      //起点
      println range.from 
      //终点
      println range.to   
      
      ===========遍历元素===========
      //使用each
      range.each {
          println it
      }
      使用for-in
      for(i in range){
          println i
      }
      
      ===========switch-case===========
      def getGrade(Number score){
          def result
          switch(score){
              case 0..<60:
                  result='不及格'
                  break;
              case 60..100:
                  result='及格'
                  break;
              default:
                  result='输入异常'
          }
          return result
      }
      println getGrade(50)
      println getGrade(80)
      println getGrade(120)

面向对象语法 

  1. 在Groovy中,所有的类都实现了GroovyObject接口
  2. 在Groovy中,所有类型默认都是public
  3. 在Groovy中,万物皆对象
    int x=1
    double y=3.14
    char ch='a'
    boolean flag=true;
    
    println x.class  //class java.lang.Integer
    println y.class  //class java.lang.Double
    println ch.class //class java.lang.Character
    println flag.class //class java.lang.Boolean
  4. Groovy会自动为属性提供set/get方法,并且会将属性私有化:
    class Person{
        String name
        Integer age
    }
    
    
    //使用
    def person = new Person()
    person.setName('Alice')
    person.setAge(18)
    println 'name:'+ person.getName() //name:Alice
    println 'age:' + person.getAge() //age:18
    1. 证明:
  5. Groovy中特有的trait关键字,类似于接口
    1. 为什么类似于接口?
      1. 看看它的class文件就知道了
      2. 可以看到DefaultAction1最后被编译成了interface
    2. trait可以包含方法(抽象方法、具体方法、私有方法)、属性
      trait DefaultAction {
          def actionName = 'trait'
          int step= 10
          abstract void eat()
      
          //void eat()  //不允许,接口中才可以 
      
          void play(){
              println 'I can play!'
          }
      
          private void test(){
              println 'test()'
          }
      }
    3. trait中的方法冲突:如果一个类实现了多个trait,并且这些trait中有同名方法,Groovy会要求类明确指定使用哪个trait的方法,或者覆盖该方法。
      trait A {
          void greet() { println "Hello from A" }
      }
      
      trait B {
          void greet() { println "Hello from B" }
      }
      
      class C implements A, B {
          void greet() {
              A.super.greet()  // 明确调用A trait中的greet方法
          }
      }
      
      def c = new C()
      c.greet()  // 输出: Hello from A
    4. trait中可以有静态方法,接口没有
      trait Logger {
          static void log(String message) {
              println "[LOG] $message"
          }
      }
      class LoggerTest implements Logger{
      }
      
      LoggerTest.log("wq")
      
      //Logger.log("wq") //这种是不允许的
    5. trait有构造方法和静态代码块,接口并没有
      trait Initializable {
          { println "Initializing trait" }
          static {
              println 'static'
          }
      }
      
      class MyClass implements Initializable {
          MyClass() {
              println "Initializing class"
          }
      }
      
      def obj = new MyClass()
      //输出:
      static
      Initializing trait
      Initializing class
    6. trait还有一些注解,例如:@SelfType----注解用于限制trait只能被特定类型的类实现、@Delegate----注解可以将trait中的方法委托给另一个对象等等,这里就不一一介绍了
    7. 总结:trait类似于接口,功能比接口多

JSON解析

  1. 使用Gson:com.google.code.gson:gson:2.8.9
    Gson gson = new Gson();
    Person p1 = new Person(name:"jack",age:18)
    String json = gson.toJson(p1)
    println "json:$json"
    Person p2 = gson.fromJson(json, Person.class); 
    String jsonOutput = gson.toJson(p2); 
    println "jsonOutput:$jsonOutput" //{"name":"jack","age":18}
  2. 使用Groovy自带的json工具:JsonOutput
    //对象转成json字符串
    def list=[new Person(name:'jack',age:18),
                new Person(name:'Alice',age:18)]
    println JsonOutput.toJson(list) //[{"name":"jack","age":18},{"name":"Alice","age":18}]
    //格式化
    def json=JsonOutput.toJson(list)
    println JsonOutput.prettyPrint(json)
    
    //json字符串转成对象
    def jsonSluper=new JsonSlurper()
    def object=jsonSluper.parse("[{\"age\":18,\"name\":\"jack\"},{\"age\":18,\"name\":\"Alice\"}]".getBytes())
    println object
    
    def object2=jsonSluper.parse("[{\"abc\":\"jack\"}]".getBytes())
    println object2.abc
    
    
    
    def jsonSlurper = new JsonSlurper()
    def jsonString = '[{"name":"jack","age":18},{"name":"Alice","age":18}]'
    def jsonObject = jsonSlurper.parseText(jsonString)
    
    // 手动转换为 Person 对象
    def personList = jsonObject.collect { map ->
        new Person(name: map.name, age: map.age)
    }
    
    println personList // 输出 [Person(name: jack, age: 18), Person(name: Alice, age: 18)]

XML解析

  1. 使用Groovy自带的XmlSlurper解析xml:
    final String xml='''
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.jvm_demo_20200601">
        <test>12345</test>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".MainActivity2">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    '''
    
    //解析XML数据
    def xmlSluper=new XmlSlurper()
    def result=xmlSluper.parseText(xml)
    println result.@package //com.example.jvm_demo_20200601
    println result.test.text() //12345
    //读取有域名空间的节点
    result.declareNamespace('android':'http://schemas.android.com/apk/res/android')
    println result.application.@'android:allowBackup'  //true
    println result.application.activity[0].@'android:name'  //.MainActivity
    println result.application.activity[1].@'android:name'  //.MainActivity2
    
    //遍历XML节点
    result.application.activity.each{activity ->
        println activity.@'android:name'
    }
  2. 使用Groovy自带的MarkupBuilder生成xml格式数据
    /**
     * 生成XML格式数据
     * <html>
     *     <title id='123',name='android'>xml生成
     *          <person></person>
     *     </title>
     *     <body name='java'>
     *         <activity id='001' class='MainActivity'>abc</activity>
     *         <activity id='002' class='SecActivity'>abc</activity>
     *     </body>
     * </html>
     */
    def sw=new StringWriter()
    def xmlBuilder=new MarkupBuilder(sw)
    xmlBuilder.html(){
        title(id:'123',name:'android','xml生成'){
            person()
        }
        body(name:'java'){
            activity(id:'001',class:'MainActivity','abc')
            activity(id:'002',class:'SecActivity','abc')
        }
    }
    println sw

文件操作

def file=new File("D:\\JAVA\\Study_Groovy\\test.txt")
//遍历文件
file.eachLine { line ->
    println line
}

//返回所有文本
def text=file.getText()
println text

//以List<Stirng>返回文件的每一行
def text=file.readLines()
println text.toListString()

//以java中的流的方式读取文件内容
def reader=file.withReader{reader ->
    char[] buffer=new char[100]
    reader.read(buffer)
    return buffer
}
println reader
//写入数据
file.withWriter { writer ->
    writer.write("abc")
}

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

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

    相关文章

    Flink CDC YAML:面向数据集成的 API 设计

    摘要&#xff1a;本文整理自阿里云智能集团 、Flink PMC Member & Committer 徐榜江&#xff08;雪尽&#xff09;老师在 Flink Forward Asia 2024 数据集成&#xff08;一&#xff09;专场中的分享。主要分为以下四个方面&#xff1a; Flink CDC YAML API Transform A…

    OpenCV:视频背景减除

    目录 简述 1. MOG &#x1f537;1.1 主要特点 &#x1f537;1.2 代码示例 &#x1f537;1.3 运行效果 2. MOG2 &#x1f537;2.1 主要特点 &#x1f537;2.2 代码示例 &#x1f537;2.3 运行效果 3. KNN 4. GMG 5. CNT 6. LSBP 7. 如何选择适合的接口&#xff…

    PAT乙级( 1009 说反话 1010 一元多项式求导)C语言版本超详细解析

    1009 说反话 给定一句英语&#xff0c;要求你编写程序&#xff0c;将句中所有单词的顺序颠倒输出。 输入格式&#xff1a; 测试输入包含一个测试用例&#xff0c;在一行内给出总长度不超过 80的字符串。字符串由若干单词和若干空格组成&#xff0c;其中单词是由英文字母&#x…

    OpenCV2D 特征框架 (19)目标检测类cv::CascadeClassifier的使用

    操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::CascadeClassifier 是 OpenCV 中用于对象检测的一个核心类&#xff0c;特别适用于基于 Haar 特征和 LBP&#xff08;局部二进制模式&#xf…

    大数据学习之SparkSql

    95.SPARKSQL_简介 网址&#xff1a; https://spark.apache.org/sql/ Spark SQL 是 Spark 的一个模块&#xff0c;用于处理 结构化的数据 。 SparkSQL 特点 1 易整合 无缝的整合了 SQL 查询和 Spark 编程&#xff0c;随时用 SQL 或 DataFrame API 处理结构化数据。并且支…

    RabbitMQ 从入门到精通:从工作模式到集群部署实战(四)

    #作者&#xff1a;闫乾苓 系列前几篇&#xff1a; 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;一&#xff09;》&#xff1a;link 《RabbitMQ 从入门到精通&#xff1a;从工作模式到集群部署实战&#xff08;二&#xff09;》&#xff1a; lin…

    ip地址是手机号地址还是手机地址

    在数字化生活的浪潮中&#xff0c;IP地址、手机号和手机地址这三个概念如影随形&#xff0c;它们各自承载着网络世界的独特功能&#xff0c;却又因名称和功能的相似性而时常被混淆。尤其是“IP地址”这一术语&#xff0c;经常被错误地与手机号地址或手机地址划上等号。本文旨在…

    Django开发入门 – 0.Django基本介绍

    Django开发入门 – 0.Django基本介绍 A Brief Introduction to django By JacksonML 1. Django简介 1) 什么是Django? 依据其官网的一段解释&#xff1a; Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. …

    深度解析DeepSeek模型系列:从轻量级到超大规模(附DeepSeek硬件配置清单)

    在人工智能领域&#xff0c;深度学习模型的选择对于任务的执行效率和精度至关重要。DeepSeek模型系列提供了多种不同参数量的版本&#xff0c;以满足不同场景下的需求。本文将详细解析DeepSeek模型系列的特点、适用场景以及硬件需求。 DeepSeek模型系列概览 DeepSeek模型系列…

    树和二叉树_7

    树和二叉树_7 一、leetcode-102二、题解1.引库2.代码 一、leetcode-102 二叉树的层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 样例输入&#xff1a;root [3,9,20,null,nu…

    【DeepSeek】私有化本地部署图文(Win+Mac)

    目录 一、DeepSeek本地部署【Windows】 1、安装Ollama 2、配置环境变量 3、下载模型 4、使用示例 a、直接访问 b、chatbox网页访问 二、DeepSeek本地部署【Mac】 1、安装Ollama 2、配置环境变量 3、下载模型 4、使用示例 5、删除已下载的模型 三、DeepSeek其他 …

    <tauri><rust><GUI>基于rust和tauri,在已有的前端框架上手动集成tauri示例

    前言 本文是基于rust和tauri&#xff0c;由于tauri是前、后端结合的GUI框架&#xff0c;既可以直接生成包含前端代码的文件&#xff0c;也可以在已有的前端项目上集成tauri框架&#xff0c;将前端页面化为桌面GUI。 环境配置 系统&#xff1a;windows 10 平台&#xff1a;visu…

    每日学习 设计模式 五种不同的单例模式

    狮子大佬原文 https://blog.csdn.net/weixin_40461281/article/details/135050977 第一种 饿汉式 为什么叫饿汉,指的是"饿" 也就是说对象实例在程序启动时就已经被创建好,不管你是否需要,它都会在类加载时立即实例化,也就是说 实例化是在类加载时候完成的,早早的吃…

    从技术体系到实践案例:浪潮信息解码金融算力演进路径

    作为金融科技领域的重要参与者&#xff0c;浪潮信息作为核心参编单位&#xff0c;联合中国金电、工商银行等33家机构共同完成《中国金融科技发展报告&#xff08;2024&#xff09;》&#xff08;以下简称蓝皮书&#xff09;编撰。浪潮信息凭借在数字基础设施领域的技术积累&…

    题海拾贝:【高精度】减法

    Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 1、题…

    知识库升级新思路:用生成式AI打造智能知识助手

    在当今信息爆炸的时代&#xff0c;企业和组织面临着海量数据的处理和管理挑战。知识库管理系统&#xff08;Knowledge Base Management System, KBMS&#xff09;作为一种有效的信息管理工具&#xff0c;帮助企业存储、组织和检索知识。然而&#xff0c;传统的知识库系统往往依…

    设计模式-生产者消费者模型

    阻塞队列&#xff1a; 在介绍生产消费者模型之前&#xff0c;我们先认识一下阻塞队列。 阻塞队列是一种支持阻塞操作的队列&#xff0c;常用于生产者消费者模型&#xff0c;它提供了线程安全的队列操作&#xff0c;并且在队列为空或满时&#xff0c;能够阻塞等待&#xff0c;…

    1Panel应用推荐:WordPress开源博客软件和内容管理系统

    1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

    计算机毕业设计Tensorflow+LSTM空气质量监测及预测系统 天气预测系统 Spark Hadoop 深度学习 机器学习 人工智能

    温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

    语言月赛 202308【小粉兔做麻辣兔头】题解(AC)

    》》》点我查看「视频」详解》》》 [语言月赛 202308] 小粉兔做麻辣兔头 题目描述 粉兔喜欢吃麻辣兔头&#xff0c;麻辣兔头的辣度分为若干级&#xff0c;用数字表示&#xff0c;数字越大&#xff0c;兔头越辣。为了庆祝粉兔专题赛 #1 的顺利举行&#xff0c;粉兔要做一些麻…