目录

Groovy - 快速指南

Groovy - Overview

Groovy是一种基于Java平台的面向对象语言。 Groovy 1.0于2007年1月2日发布,Groovy 2.4作为当前主要版本发布。 Groovy通过Apache License v 2.0分发。

Groovy的特点

Groovy具有以下功能 -

  • 支持静态和动态类型。
  • 支持运算符重载。
  • 列表和关联数组的本机语法。
  • 对正则表达式的本机支持。
  • 对各种标记语言(如XML和HTML)的本机支持。
  • Groovy对Java开发人员来说很简单,因为Java和Groovy的语法非常相似。
  • 您可以使用现有的Java库。
  • Groovy扩展了java.lang.Object。

Groovy的官方网站是http://www.groovy-lang.org/

Groovy官方网站

Groovy - Environment

有多种方法可以获得Groovy环境。

Binary download and installation - 访问链接www.groovy-lang.org/download.html以获取Windows Installer部分。 单击此选项可开始下载Groovy安装程序。

Groovy环境设置

启动安装程序后,请按照以下步骤完成安装。

Step 1 - 选择语言安装程序。

语言安装程序

Step 2 - 单击下一个屏幕中的“下一步”按钮。

Groovy 2.4.5安装程序

Step 3 - 单击“我同意”按钮。

许可协议

Step 4 - 接受默认组件,然后单击“下一步”按钮。

选择组件

Step 5 - 选择适当的目标文件夹,然后单击“下一步”按钮。

安装位置

Step 6 - 单击“安装”按钮开始安装。

开始菜单文件夹

Step 7 - 安装完成后,单击“下一步”按钮开始配置。

安装完成

Step 8 - 选择默认选项,然后单击“下一步”按钮。

环境变量

Step 9 - 接受默认文件关联,然后单击“下一步”按钮。

文件关联

Step 10 - 单击“完成”按钮以完成安装。

完成按钮

完成上述步骤后,您就可以启动groovy shell,它是Groovy安装的一部分,有助于测试我们Groovy语言的不同方面,而无需为Groovy提供完善的集成开发环境。 这可以通过从命令提示符运行命令groovysh来完成。

运行命令Groovysh

如果要将groovy二进制文件包含在maven或gradle构建中,可以添加以下行

Gradle

'org.codehaus.groovy:groovy:2.4.5'

Maven

<groupId>org.codehaus.groovy</groupId> 
<artifactId>groovy</artifactId>  
<version>2.4.5</version>

Groovy - Basic Syntax

为了理解Groovy的基本语法,让我们首先看一个简单的Hello World程序。

创建您的第一个Hello World计划

创建您的第一个hello world程序就像输入以下代码行一样简单 -

class Example {
   static void main(String[] args) {
      // Using a simple println statement to print output to the console
      println('Hello World');
   }
}

当我们运行上述程序时,我们将得到以下结果 -

Hello World

在Groovy中导入语句

import语句可用于导入可在代码中使用的其他库的功能。 这是通过使用import关键字完成的。

下面的示例演示如何使用MarkupBuilder类的简单导入,该类可能是用于创建HTML或XML标记的最常用类之一。

import groovy.xml.MarkupBuilder 
def xml = new MarkupBuilder() 

默认情况下,Groovy在代码中包含以下库,因此您无需显式导入它们。

import java.lang.* 
import java.util.* 
import java.io.* 
import java.net.* 
import groovy.lang.* 
import groovy.util.* 
import java.math.BigInteger 
import java.math.BigDecimal

Groovy中的标记

标记是关键字,标识符,常量,字符串文字或符号。

println(“Hello World”);

在上面的代码行中,有两个标记,第一个是关键字println,第二个是“Hello World”的字符串文字。

Groovy中的评论

注释用于记录您的代码。 Groovy中的注释可以是单行或多行。

通过在行中的任何位置使用//来标识单行注释。 一个例子如下所示 -

class Example {
   static void main(String[] args) {
      // Using a simple println statement to print output to the console
      println('Hello World');
   }
}

多行注释在开头用/ *标识,* /用于标识多行注释的结尾。

class Example {
   static void main(String[] args) {
      /* This program is the first program
      This program shows how to display hello world */
      println('Hello World');
   }
}

分号(Semicolons)

就像Java编程语言一样,需要使用分号来区分Groovy中定义的多个语句。

class Example {
   static void main(String[] args) {
      // One can see the use of a semi-colon after each statement
      def x = 5;
      println('Hello World');  
   }
}

上面的例子显示分号用于区分不同的代码行语句。

标识符 (Identifiers)

标识符用于定义变量,函数或其他用户定义的变量。 标识符以字母,美元或下划线开头。 他们不能以数字开头。 以下是有效标识符的一些示例 -

def employeename 
def student1 
def student_name

其中def是Groovy中用于定义标识符的关键字。

以下是如何在我们的Hello World程序中使用标识符的代码示例。

class Example {
   static void main(String[] args) {
      // One can see the use of a semi-colon after each statement
      def x = 5;
      println('Hello World'); 
   }
}

在上面的例子中,变量x用作标识符。

关键字 (Keywords)

名称建议的关键字是Groovy编程语言中保留的特殊字。 下表列出了Groovy中定义的关键字。

asassertbreakcase
catchclassconstcontinue
defdefaultdoelse
enumextendsfalseFinally
forgotoifimplements
importininstanceofinterface
newpullpackagereturn
superswitchthisthrow
throwstraittruetry
while

Whitespaces

Whitespace是Java和Groovy等编程语言中使用的术语,用于描述空格,制表符,换行符和注释。 空白将语句的一部分与另一部分分开,并使编译器能够识别语句中的一个元素。

例如,在以下代码示例中,关键字def和变量x之间存在空格。 这样编译器就知道def是需要使用的关键字,x应该是需要定义的变量名。

def x = 5;

Literals

文字是在groovy中表示固定值的符号。 groovy语言包含整数,浮点数,字符和字符串的符号。 以下是Groovy编程语言中的一些文字示例 -

12 
1.45 
‘a’ 
“aa”

Groovy - Data Types

在任何编程语言中,您都需要使用各种变量来存储各种类型的信息。 变量只是用于存储值的保留内存位置。 这意味着在创建变量时,您在内存中保留一些空间以存储与变量关联的值。

您可能希望存储各种数据类型的信息,如字符串,字符,宽字符,整数,浮点,布尔值等。根据变量的数据类型,操作系统分配内存并决定可以在保留中存储的内容记忆。

(类型)

Groovy提供各种内置数据类型。 以下是Groovy中定义的数据类型列表 -

  • byte - 用于表示字节值。 一个例子是2。

  • short - 用于表示短数字。 一个例子是10。

  • int - 用于表示整数。 一个例子是1234。

  • long - 用于表示长数字。 一个例子是10000090。

  • float - 用于表示32位浮点数。 一个例子是12.34。

  • double - 用于表示64位浮点数,这些浮点数是较长的十进制数表示,有时可能需要这些数字。 一个例子是12.3456565。

  • char - 这定义了单个字符文字。 一个例子是'a'。

  • Boolean - 这表示一个布尔值,可以是true或false。

  • String - 这些是以String the form表示的文本文字。 例如“Hello World”。

绑定值

下表显示了数字和小数文字的最大允许值。

byte-128 to 127
short-32,768 to 32,767
int-2,147,483,648 to 2,147,483,647
long -9,223,372,036,854,775,808至+ 9,223,372,036,854,775,807
float 1.40129846432481707e-45至3.40282346638528860e + 38
double 4.94065645841246544e-324d至1.79769313486231570e + 308d

类数字

类型除了基本类型之外,还允许使用以下对象类型(有时称为包装类型) -

  • java.lang.Byte
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double

此外,以下类可用于支持任意精度算术 -

名称 描述
java.math.BigInteger 不可变的任意精度有符号整数 30g
java.math.BigDecimal 不可变的任意精度带符号十进制数 3.5g

以下代码示例展示了如何使用不同的内置数据类型 -

class Example { 
   static void main(String[] args) { 
      //Example of a int datatype 
      int x = 5; 
      //Example of a long datatype 
      long y = 100L; 
      //Example of a floating point datatype 
      float a = 10.56f; 
      //Example of a double datatype 
      double b = 10.5e40; 
      //Example of a BigInteger datatype 
      BigInteger bi = 30g; 
      //Example of a BigDecimal datatype 
      BigDecimal bd = 3.5g; 
      println(x); 
      println(y); 
      println(a); 
      println(b); 
      println(bi); 
      println(bd); 
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

5 
100 
10.56 
1.05E41 
30 
3.5

Groovy - Variables

Groovy中的变量可以通过两种方式定义 - 使用数据类型的native syntax ,或者by using the def keyword 。 对于变量定义,必须明确提供类型名称或替换使用“def”。 这是Groovy解析器所必需的。

Groovy中有以下基本类型的变量,如前一章所述 -

  • byte - 用于表示字节值。 一个例子是2。

  • short - 用于表示短数字。 一个例子是10。

  • int - 用于表示整数。 一个例子是1234。

  • long - 用于表示长数字。 一个例子是10000090。

  • float - 用于表示32位浮点数。 一个例子是12.34。

  • double - 用于表示64位浮点数,这些浮点数是较长的十进制数表示,有时可能需要这些数字。 一个例子是12.3456565。

  • char - 这定义了单个字符文字。 一个例子是'a'。

  • Boolean - 这表示一个布尔值,可以是true或false。

  • String - 这些是以String the form表示的文本文字。 例如“Hello World”。

Groovy还允许其他类型的变量,如数组,结构和类,我们将在后续章节中看到。

变量声明

变量声明告诉编译器为变量创建存储的位置和数量。

以下是变量声明的示例 -

class Example { 
   static void main(String[] args) { 
      // x is defined as a variable 
      String x = "Hello";
      // The value of the variable is printed to the console 
      println(x);
   }
}

当我们运行上述程序时,我们将得到以下结果 -

Hello

命名变量 (Naming Variables)

变量的名称可以由字母,数字和下划线字符组成。 它必须以字母或下划线开头。 大写和小写字母是不同的,因为Groovy,就像Java一样是区分大小写的编程语言。

class Example { 
   static void main(String[] args) { 
      // Defining a variable in lowercase  
      int x = 5;
      // Defining a variable in uppercase  
      int X = 6; 
      // Defining a variable with the underscore in it's name 
      def _Name = "Joe"; 
      println(x); 
      println(X); 
      println(_Name); 
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

5 
6 
Joe 

我们可以看到xX是两个不同的变量,因为区分大小写,在第三种情况下,我们可以看到_Name以下划线开头。

打印变量

您可以使用println函数打印变量的当前值。 以下示例显示了如何实现此目的。

class Example { 
   static void main(String[] args) { 
      //Initializing 2 variables 
      int x = 5; 
      int X = 6; 
      //Printing the value of the variables to the console 
      println("The value of x is " + x + "The value of X is " + X);  
   }
}

当我们运行上述程序时,我们将得到以下结果 -

The value of x is 5 The value of X is 6 

Groovy - Operators

运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。

Groovy有以下类型的运算符 -

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 分配运算符

算术运算符 (Arithmetic Operators)

Groovy语言支持普通的算术运算符作为任何语言。 以下是Groovy中可用的算术运算符 -

显示示例

操作者 描述
+ 增加了两个操作数 1 + 2将给出3
从第一个减去第二个操作数 2 - 1将给出1
* 两个操作数的乘法 2 * 2将给4
/ 由分母划分的分子 3/2会给1.5
% 模数运算符和整数/浮点除法后的余数 3%2将给1
++ 增量运算符用于将操作数的值递增1

int x = 5;

X ++;

x将给出6

-- 增量运算符用于将操作数的值减1

int x = 5;

X - ;

x将给出4

关系运算符

关系运算符允许对象的比较。 以下是Groovy中可用的关系运算符 -

显示示例

操作者 描述
== 测试两个对象之间的相等性 2 == 2将给出真实
!= 测试两个对象之间的差异 3!= 2将给出真实
< 检查左对象是否小于右操作数。 2 <3将给出真实
<= 检查左对象是否小于或等于右操作数。 2 <= 3将给出真实
> 检查左对象是否大于右操作数。 3> 2将给出真实
>= 检查左对象是否大于或等于右操作数。 3> = 2将给出真实

逻辑运算符 (Logical Operators)

逻辑运算符用于计算布尔表达式。 以下是Groovy中可用的逻辑运算符 -

显示示例

操作者 描述
&& 这是逻辑“和”运算符 true && true将给出真实
|| 这是逻辑“或”运算符 真|| 真的会给出真实的
! 这是逻辑“非”运算符 !false will give true

按位运算符 (Bitwise Operators)

Groovy提供了四个按位运算符。 以下是Groovy中可用的按位运算符 -

显示示例

Sr.No 操作符和说明
1

&

这是按位“和”运算符

2

|

这是按位“或”运算符

3

^

这是按位“xor”或Exclusive或运算符

4

~

这是按位否定运算符

这是展示这些运算符的真值表。

p q p&q p | q p ^ q
00000
01011
11110
10011

分配运算符

Groovy语言还提供赋值运算符。 以下是Groovy中可用的赋值运算符 -

显示示例

操作者 描述
+= 这会向左操作数添加右操作数,并将结果赋给左操作数。

def A = 5

A + = 3

输出将是8

-= 这会从左操作数中减去右操作数,并将结果赋给左操作数

def A = 5

A- = 3

输出为2

*= 这将右操作数与左操作数相乘,并将结果赋给左操作数

def A = 5

A * = 3

输出将是15

/= 这将左操作数与右操作数分开,并将结果赋给左操作数

def A = 6

A/= 3

输出为2

%= 这将使用两个操作数获取模数,并将结果分配给左操作数

def A = 5

A%= 3

输出为2

范围运算符

Groovy支持范围的概念,并在..符号的帮助下提供范围运算符的表示法。 下面给出了范围算子的一个简单例子。

def range = 0..5 

这只是定义了一个简单的整数范围,存储在一个名为range的局部变量中,下限为0,上限为5。

以下代码段显示了如何使用各种运算符。

class Example { 
   static void main(String[] args) { 
      def range = 5..10; 
      println(range); 
      println(range.get(2)); 
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

println语句中,您可以看到显示在范围语句中定义的整个数字范围。

get语句用于从定义的范围中获取一个对象,该对象将索引值作为参数。

[5, 6, 7, 8, 9, 10] 
7

运算符优先级 (Operator Precedence)

下表按优先顺序列出了所有groovy运算符。

Sr.No 运算符和名称
1

++ -- + -

预增/减,一元加,一元减

2

*/%

乘,div,modulo

3

+ -

另外,减法

4

== != 《=》

等于,不等于,比较

5

&

二进制/按位和

6

^

二进制/按位xor

7

|

二进制/按位或

8

&&

合乎逻辑的

9

||

逻辑或

10

= **= *= /= %= += -= 《《= 》》= 》》》= &= ^= |=

各种赋值运算符

Groovy - Loops

到目前为止,我们已经看到了以顺序方式一个接一个地执行的语句。 另外,Groovy中提供了一些语句来改变程序逻辑中的控制流。 然后将它们分类为控制语句流程,我们将详细介绍。

S.No. 声明和说明
1 for Statement

通过首先计算条件表达式(布尔值)来执行while语句,如果结果为true,则执行while循环中的语句。

2 for Statement

for语句用于迭代一组值。

3 for-in Statement

for-in语句用于迭代一组值。

循环控制语句 (Loop Control Statements)

S.No. 声明和说明
1 Break Statement

break语句用于改变循环和switch语句中的控制流。

2 continue语句

continue语句补充了break语句。 它的使用仅限于while和for循环。

Groovy - Decision Making

决策结构要求程序员指定一个或多个要由程序评估或测试的条件,以及在条件被确定为true要执行的语句,以及可选的其他语句,如果条件被确定为false

Sr.No. 声明和说明
1 if Statement

该陈述的一般工作是首先在if语句中评估条件。 如果条件为真,则执行语句。

2 if/else声明

该陈述的一般工作是首先在if语句中评估条件。 如果条件为真,则它然后执行语句并在else条件之前停止并退出循环。 如果条件为false,则执行else语句块中的语句,然后退出循环。

3 嵌套If语句

有时需要将多个if语句嵌入到彼此内部。

4 Switch Statement

有时,嵌套的if-else语句是如此常见,并且经常被使用,因此设计了一个更简单的语句,称为switch语句。

5 嵌套的Switch语句

也可以有一组嵌套的switch语句。

Groovy - Methods

Groovy中的方法定义为返回类型或def关键字。 方法可以接收任意数量的参数。 在定义参数时,没有必要明确定义类型。 可以添加公共,私有和受保护的修饰符。 默认情况下,如果未提供可见性修饰符,则该方法为public。

最简单的方法类型是没有参数的方法,如下所示 -

def methodName() { 
   //Method code 
}

以下是简单方法的示例

class Example {
   static def DisplayName() {
      println("This is how methods work in groovy");
      println("This is an example of a simple method");
   } 
   static void main(String[] args) {
      DisplayName();
   } 
}

在上面的示例中,DisplayName是一个简单的方法,它由两个println语句组成,用于将一些文本输出到控制台。 在我们的静态main方法中,我们只是调用DisplayName方法。 上述方法的输出将是 -

This is how methods work in groovy 
This is an example of a simple method

方法参数

如果方法的行为由一个或多个参数的值确定,则该方法通常更有用。 我们可以使用方法参数将值传递给被调用的方法。 请注意,参数名称必须彼此不同。

参数最简单的方法类型如下所示 -

def methodName(parameter1, parameter2, parameter3) { 
   // Method code goes here 
}

以下是带参数的简单方法示例

class Example {
   static void sum(int a,int b) {
      int c = a+b;
      println(c);
   }  
   static void main(String[] args) {
      sum(10,5);
   } 
}

在这个例子中,我们创建了一个带有2个参数ab的求和方法。 这两个参数都是int类型。 然后我们从main方法调用sum方法并将值传递给变量ab

上述方法的输出值为15。

默认参数

Groovy中还有一项规定,即为方法中的参数指定默认值。 如果没有值传递给参数的方法,则使用默认值。 如果同时使用了非默认参数和默认参数,则必须注意,应在参数列表的末尾定义默认参数。

以下是带参数的简单方法示例 -

def someMethod(parameter1, parameter2 = 0, parameter3 = 0) { 
   // Method code goes here 
} 

让我们看看我们之前看到的添加两个数字的相同示例,并创建一个具有一个默认参数和另一个非默认参数的方法 -

class Example { 
   static void sum(int a,int b = 5) { 
      int c = a+b; 
      println(c); 
   } 
   static void main(String[] args) {
      sum(6); 
   } 
}

在这个例子中,我们创建了一个带有两个参数ab的求和方法。 这两个参数都是int类型。 这个例子和前面例子之间的区别在于,在这种情况下,我们将b的默认值指定为5.因此,当我们从main方法调用sum方法时,我们可以选择只传递一个值为6的值,这将被分配给sum方法中的参数a

上述方法的输出值为11。

class Example {
   static void sum(int a,int b = 5) {
      int c = a+b;
      println(c);
   } 
   static void main(String[] args) {
      sum(6,6);
   } 
}

我们也可以通过传递2个值来调用sum方法,在上面的示例中,我们传递2个值为6.第二个值6实际上将替换分配给参数b的默认值。

上述方法的输出值为12。

方法返回值

方法还可以将值返回给调用程序。 这在现代编程语言中是必需的,其中方法进行某种计算,然后将所需值返回给调用方法。

以下是具有返回值的简单方法的示例。

class Example {
   static int sum(int a,int b = 5) {
      int c = a+b;
      return c;
   } 
   static void main(String[] args) {
      println(sum(6));
   } 
}

在上面的例子中,请注意,这次我们为方法sum指定一个类型为int的返回类型。 在该方法中,我们使用return语句将sum值发送到调用主程序。 由于方法的值现在可用于main方法,因此我们使用println函数在控制台中显示该值。

上述方法的输出值为11。

实例方法 (Instance methods)/h2>

方法通常在Groovy中的类中实现,就像Java语言一样。 类只是用于创建定义其属性和行为的不同对象的蓝图或模板。 类对象展示了由其类定义的属性和行为。 因此,通过在类内部创建方法来定义行为。

我们将在后面的章节中更详细地看到类,但是以下是类中方法实现的示例。 在前面的示例中,我们将方法定义为静态方法,这意味着我们可以直接从类中访问这些方法。 下一个方法示例是实例方法,其中通过创建类的对象来访问方法。 我们将在后面的章节中再次看到类,现在我们将演示如何使用方法。

以下是如何实现方法的示例。

class Example { 
   int x; 
   public int getX() { 
      return x; 
   } 
   public void setX(int pX) { 
      x = pX; 
   } 
   static void main(String[] args) { 
      Example ex = new Example(); 
      ex.setX(100); 
      println(ex.getX()); 
   } 
}

在上面的例子中,请注意,这次我们没有为类方法指定静态属性。 在我们的main函数中,我们实际上是创建Example类的一个实例,然后调用'ex'对象的方法。

上述方法的输出值为100。

本地和外部参数名称

Groovy像java一样提供了具有本地和全局参数的工具。 在以下示例中, lx是一个局部参数,其范围仅在getX()函数内, x是一个全局属性,可以在整个Example类中访问。 如果我们尝试在getX()函数之外访问变量lx ,我们将得到一个错误。

class Example { 
   static int x = 100; 
   public static int getX() { 
      int lx = 200; 
      println(lx); 
      return x; 
   } 
   static void main(String[] args) { 
      println(getX()); 
   }  
}

当我们运行上述程序时,我们将得到以下结果。

200 
100

这个方法适用于Properties

就像在Java中一样,groovy可以使用this关键字访问其实例成员。 以下示例显示了当我们使用this.x语句时,它引用了它的实例并相应地设置了x的值。

class Example { 
   int x = 100; 
   public int getX() { 
      this.x = 200; 
      return x; 
   } 
   static void main(String[] args) {
      Example ex = new Example(); 
      println(ex.getX());
   }
}

当我们运行上面的程序时,我们将在控制台上打印出200的结果。

Groovy - File I/O

在使用I/O时,Groovy提供了许多辅助方法。 Groovy提供了更简单的类来为文件提供以下功能。

  • 读文件
  • 写入文件
  • 遍历文件树
  • 读取和写入数据对象到文件

除此之外,您始终可以使用下面列出的常规Java类进行文件I/O操作。

  • java.io.File
  • java.io.InputStream
  • java.io.OutputStream
  • java.io.Reader
  • java.io.Writer

读文件

以下示例将输出Groovy中文本文件的所有行。 方法eachLine是在Groovy的File类中内置的,目的是确保读取文本文件的每一行。

import java.io.File 
class Example { 
   static void main(String[] args) { 
      new File("E:/Example.txt").eachLine {  
         line -> println "line : $line"; 
      } 
   } 
}

File类用于实例化一个以文件名作为参数的新对象。 然后它接受eachLine的功能,将其放入一个名为line的变量并相应地打印它。

如果文件包含以下行,则将打印它们。

line : Example1
line : Example2

将文件内容作为整个字符串读取

如果要将文件的全部内容作为字符串获取,可以使用文件类的text属性。 以下示例显示了如何完成此操作。

class Example { 
   static void main(String[] args) { 
      File file = new File("E:/Example.txt") 
      println file.text 
   } 
}

如果文件包含以下行,则将打印它们。

line : Example1 
line : Example2

写入文件

如果要写入文件,则需要使用writer类将文本输出到文件。 以下示例显示了如何完成此操作。

import java.io.File 
class Example { 
   static void main(String[] args) { 
      new File('E:/','Example.txt').withWriter('utf-8') { 
         writer -> writer.writeLine 'Hello World' 
      }  
   } 
}

如果您打开文件Example.txt,您将看到打印到文件中的“Hello World”字样。

获取文件的大小

如果要获取文件的大小,可以使用文件类的length属性来获取文件的大小。 以下示例显示了如何完成此操作。

class Example {
   static void main(String[] args) {
      File file = new File("E:/Example.txt")
      println "The file ${file.absolutePath} has ${file.length()} bytes"
   } 
}

上面的代码将以字节为单位显示文件的大小。

测试文件是否是目录

如果要查看路径是文件还是目录,可以使用File类的isFileisDirectory选项。 以下示例显示了如何完成此操作。

class Example { 
   static void main(String[] args) { 
      def file = new File('E:/') 
      println "File? ${file.isFile()}" 
      println "Directory? ${file.isDirectory()}" 
   } 
}

上面的代码将显示以下输出 -

File? false 
Directory? True

创建目录

如果要创建新目录,可以使用File类的mkdir函数。 以下示例显示了如何完成此操作。

class Example {
   static void main(String[] args) {
      def file = new File('E:/Directory')
      file.mkdir()
   } 
}

如果目录E:\Directory不存在,则将创建该目录。

删除文件

如果要删除文件,可以使用File类的delete功能。 以下示例显示了如何完成此操作。

class Example {
   static void main(String[] args) {
      def file = new File('E:/Example.txt')
      file.delete()
   } 
}

如果文件存在,该文件将被删除。

复制文件

Groovy还提供将内容从一个文件复制到另一个文件的功能。 以下示例显示了如何完成此操作。

class Example {
   static void main(String[] args) {
      def src = new File("E:/Example.txt")
      def dst = new File("E:/Example1.txt")
      dst << src.text
   } 
}

将创建文件Example1.txt,并将文件Example.txt的所有内容复制到此文件中。

获取目录内容

Groovy还提供列出驱动器中的驱动器和文件的功能。

以下示例显示如何使用File类的listRoots函数显示计算机上的驱动器。

class Example { 
   static void main(String[] args) { 
      def rootFiles = new File("test").listRoots() 
      rootFiles.each { 
         file -> println file.absolutePath 
      }
   }
}

根据机器上可用的驱动器,输出可能会有所不同。 在标准机器上,输出类似于以下输出 -

C:\ 
D:\

以下示例说明如何使用File类的eachFile函数列出特定目录中的文件。

class Example {
   static void main(String[] args) {
      new File("E:/Temp").eachFile() {  
         file->println file.getAbsolutePath()
      }
   } 
}

输出将显示目录E:\Temp中的所有文件

如果要递归显示目录及其子目录中的所有文件,则可以使用File类的eachFileRecurse函数。 以下示例显示了如何完成此操作。

class Example { 
   static void main(String[] args) {
      new File("E:/temp").eachFileRecurse() {
         file -> println file.getAbsolutePath()
      }
   }
} 

输出将显示目录E:\Temp及其子目录中的所有文件(如果存在)。

Groovy - Optionals

Groovy是一种“可选”类型的语言,在理解语言的基础知识时,这种区别很重要。 与Java(一种“强”类型语言)相比,编译器知道每个变量的所有类型,并且可以在编译时理解和遵守合同。 这意味着可以在编译时确定方法调用。

在Groovy中编写代码时,开发人员可以灵活地提供类型或不提供类型。 这可以提供一些简单的实现,并且在正确使用时,可以以强大且动态的方式为您的应用程序提供服务。

在Groovy中,可选的输入是通过'def'关键字完成的。 以下是def方法的使用示例 -

class Example { 
   static void main(String[] args) { 
      // Example of an Integer using def 
      def a = 100; 
      println(a); 
      // Example of an float using def 
      def b = 100.10; 
      println(b); 
      // Example of an Double using def 
      def c = 100.101; 
      println(c);
      // Example of an String using def 
      def d = "HelloWorld"; 
      println(d); 
   } 
} 

从上面的程序中,我们可以看到我们没有将各个变量声明为Integer,float,double或string,即使它们包含这些类型的值。

当我们运行上述程序时,我们将得到以下结果 -

100 
100.10 
100.101
HelloWorld

可选类型在开发期间可以是一个强大的实用程序,但是当代码变得过于庞大和复杂时,可能会在开发的后期阶段导致可维护性问题。

要了解如何在不使代码库陷入无法维护的混乱中使用Groovy中的可选类型,最好在应用程序中采用“duck typing”的理念。

如果我们使用duck typing重写上面的代码,它看起来就像下面给出的那样。 变量名称的名称类似于它们所代表的类型,这使得代码更容易理解。

class Example { 
   static void main(String[] args) { 
      // Example of an Integer using def 
      def aint = 100; 
      println(aint); 
      // Example of an float using def 
      def bfloat = 100.10; 
      println(bfloat); 
      // Example of an Double using def 
      def cDouble = 100.101; 
      println(cDouble);
      // Example of an String using def 
      def dString = "HelloWorld"; 
      println(dString); 
   } 
}

Groovy - Numbers

在Groovy中,Numbers实际上表示为对象,所有这些都是Integer类的实例。 要使对象执行某些操作,我们需要调用其类中声明的方法之一。

Groovy支持整数和浮点数。

  • 整数是不包含分数的值。
  • 浮点数是包含小数部分的十进制值。

Groovy中的数字示例如下所示 -

Integer x = 5; 
Float y = 1.25; 

其中x是Integer类型, y是float。

将groovy中的数字定义为对象的原因通常是因为需要对数字执行操作。 在原始类型上提供类的概念称为包装类。

默认情况下,Groovy中提供了以下包装类。

包装类

包装类的对象包含或包装其各自的基本数据类型。 将原始数据类型转换为对象的过程称为装箱,编译器会对此进行处理。 将对象转换回其对应的基本类型的过程称为拆箱。

例子 (Example)

以下是装箱和拆箱的示例 -

class Example { 
   static void main(String[] args) {
      Integer x = 5,y = 10,z = 0; 
      // The the values of 5,10 and 0 are boxed into Integer types 
      // The values of x and y are unboxed and the addition is performed 
      z = x+y; 
      println(z);
   }
}

上述程序的输出为15.在上面的例子中,首先将5,10和0的值装入整数变量x,y和z中。 然后,当执行x和y的添加时,值将从其Integer类型中取消装箱。

Number Methods

由于Groovy中的Numbers表示为类,因此以下是可用方法的列表。

S.No. 方法和描述
1 xxxValue()

此方法将Number作为参数,并根据调用的方法返回基本类型。

2 compareTo()

compareTo方法是使用一个数字与另一个数字进行比较。 如果要比较数字的值,这很有用。

3 equals()

该方法确定调用方法的Number对象是否等于作为参数传递的对象。

4 valueOf()

valueOf方法返回相关的Number Object,其中包含传递的参数的值。

5 toString()

该方法用于获取表示Number对象值的String对象。

6 parseInt()

此方法用于获取某个String的原始数据类型。 parseXxx()是一个静态方法,可以有一个或两个参数。

7 abs()

该方法给出了参数的绝对值。 参数可以是int,float,long,double,short,byte。

8 ceil()

方法ceil给出大于或等于参数的最小整数。

9 floor()

方法floor提供小于或等于参数的最大整数。

10 rint()

方法rint返回值最接近参数的整数。

11 round()

round方法返回最接近的long或int,由方法返回类型给出。

12 min()

该方法给出了两个参数中较小的一个。 参数可以是int,float,long,double。

13 max()

该方法给出了两个参数的最大值。 参数可以是int,float,long,double。

14 exp()

该方法将自然对数e的基数返回到参数的幂。

15 log()

该方法返回参数的自然对数。

16 pow()

该方法将第一个参数的值返回到第二个参数的幂。

17 sqrt()

该方法返回参数的平方根。

18 sin()

该方法返回指定double值的正弦值。

19 cos()

该方法返回指定double值的余弦值。

20 tan()

该方法返回指定double值的正切值。

21 asin()

该方法返回指定double值的反正弦值。

22 acos()

该方法返回指定double值的反余弦值。

23 atan()

该方法返回指定double值的反正切值。

24 atan2()

该方法将直角坐标(x,y)转换为极坐标(r,theta)并返回theta。

25 toDegrees()

该方法将参数值转换为度。

26 radian()

该方法将参数值转换为弧度。

27 random()

该方法用于生成介于0.0和1.0之间的随机数。 范围是:0.0 = 通过使用算术可以实现不同的范围。

Groovy - Strings

通过将字符串文本括在引号中,在Groovy中构造String文字。

Groovy提供了多种表示String文字的方法。 Groovy中的字符串可以用单引号('),双引号(“)或三引号(”“”)括起来。 此外,由三引号括起的Groovy字符串可能跨越多行。

以下是Groovy中字符串用法的示例 -

class Example { 
   static void main(String[] args) { 
      String a = 'Hello Single'; 
      String b = "Hello Double"; 
      String c = "'Hello Triple" + "Multiple lines'";
      println(a); 
      println(b); 
      println(c); 
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

Hello Single 
Hello Double 
'Hello TripleMultiple lines'

字符串索引

Groovy中的字符串是一个有序的字符序列。 字符串中的单个字符可以通过其位置访问。 这是由指数位置给出的。

字符串索引从零开始,并以小于字符串长度的一个结束。 Groovy还允许负数索引从字符串的末尾开始计数。

以下是在Groovy中使用字符串索引的示例 -

class Example { 
   static void main(String[] args) { 
      String sample = "Hello world"; 
      println(sample[4]); // Print the 5 character in the string
      //Print the 1st character in the string starting from the back 
      println(sample[-1]); 
      println(sample[1..2]);//Prints a string starting from Index 1 to 2 
      println(sample[4..2]);//Prints a string starting from Index 4 back to 2 
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

o 
d 
el 
oll 

基本字符串操作

首先让我们学习groovy中的基本字符串操作。 它们如下。

S.No. 字符串操作和描述
1 两个字符串的连接

字符串的串联可以通过简单的“+”运算符完成。

2 字符串重复

字符串的重复可以通过简单的'*'运算符完成。

3 字符串长度

字符串的长度由字符串的length()方法确定。

字符串的方法 (String Methods)

以下是String类支持的方法列表。

S.No. 方法和描述
1 center()

返回一个长度为numberOfChars的新String,其中包含左侧和右侧填充的收件人,并带有空格字符。

2 compareToIgnoreCase()

按字典顺序比较两个字符串,忽略大小写差异。

3 concat()

将指定的String连接到此String的末尾。

4 eachMatch()

处理每个正则表达式组(参见下一节)匹配给定String的子字符串。

5 endsWith()

测试此字符串是否以指定的后缀结尾。

6 equalsIgnoreCase()

将此String与另一个String进行比较,忽略大小写。

7 getAt()

它返回索引位置的字符串值

8 indexOf()

返回指定子字符串第一次出现的String中的索引。

9 matches()

它输出String是否与给定的正则表达式匹配。

10 minus()

删除String的值部分。

11 next()

++运算符为类String调用此方法。 它会递增给定String中的最后一个字符。

12 padLeft()

填充字符串,并在左侧添加空格。

13 padRight()

填充字符串,并在右侧添加空格。

14 plus()

附加一个字符串

15 previous()

这个方法由 - 运算符调用CharSequence。

16 replaceAll()

用该文本上的闭包结果替换所有出现的捕获组。

17 reverse()

创建一个与此String相反的新String。

18 split()

围绕给定正则表达式的匹配拆分此String。

19 subString()

返回一个新String,它是此String的子字符串。

20 toUpperCase()

将此String中的所有字符转换为大写。

21 toLowerCase()

将此String中的所有字符转换为小写。

Groovy - Ranges

范围是指定值序列的简写。 范围由序列中的第一个和最后一个值表示,范围可以是包含的或排他的。 包含范围包括从第一个到最后一个的所有值,而独占范围包括除最后一个之外的所有值。 以下是范围文字的一些示例 -

  • 1..10 - 包含范围的示例
  • 1 .. <10 - 独家范围的一个例子
  • 'a'..'x' - 范围也可以包含字符
  • 10..1 - 范围也可以按降序排列
  • 'x'..'a' - 范围也可以由字符组成,并且按降序排列。

以下是范围可用的各种方法。

Sr.No. 方法和描述
1 contains()

检查范围是否包含特定值

2 get()

返回此Range中指定位置的元素。

3 getFrom()

获取此范围的较低值。

4 getTo()

获取此范围的上限值。

5 isReverse()

这是一个反向的范围,向后迭代

6 size()

返回此Range中的元素数。

7 subList()

返回指定fromIndex(包含)和toIndex(不包括)之间此Range的部分视图

Groovy - Lists

List是用于存储数据项集合的结构。 在Groovy中,List包含一系列对象引用。 List中的对象引用占据序列中的位置,并由整数索引区分。 List文本显示为由逗号分隔并用方括号括起来的一系列对象。

要处理列表中的数据,我们必须能够访问各个元素。 使用索引运算符[]索引Groovy列表。 列表索引从零开始,它指的是第一个元素。

以下是一些列表示例 -

  • [11,12,13,14] - 整数值列表
  • ['Angular','Groovy','Java'] - 字符串列表
  • [1,2,[3,4],5] - 嵌套列表
  • ['Groovy',21,2.11] - 一个异构的对象引用列表
  • [] - 一个空列表

在本章中,我们将讨论Groovy中可用的列表方法。

Sr.No. 方法和描述
1 add()

将新值附加到此列表的末尾。

2 contains()

如果此List包含指定的值,则返回true。

3 get()

返回此List中指定位置的元素。

4 isEmpty()

如果此List不包含任何元素,则返回true

5 minus()

创建一个由原始元素组成的新List,而不包含集合中指定的元素。

6 plus()

创建一个新的List,由原始元素和集合中指定的元素组成。

7 pop()

从此列表中删除最后一项

8 remove()

删除此List中指定位置的元素。

9 reverse()

创建一个与原始List的元素相反的新List

10 size()

获得此列表中的元素数量。

11 sort()

返回原始List的排序副本。

Groovy - Maps

Map(也称为关联数组,字典,表和散列)是对象引用的无序集合。 Map集合中的元素由键值访问。 Map中使用的键可以是任何类。 当我们插入Map集合时,需要两个值:键和值。

以下是地图的一些示例 -

  • ['TopicName':'Lists','TopicName':'Maps'] - 以TopicName为键及其各自值的键值对的集合。

  • [:] - 空地图。

在本章中,我们将讨论Groovy中可用的映射方法。

Sr.No. 方法和描述
1 containsKey()

这张地图是否包含此密钥?

2 get()

在此Map中查找键并返回相应的值。 如果此Map中没有用于键的条目,则返回null。

3 keySet()

在此Map中获取一组键。

4 put()

将指定的值与此Map中的指定键相关联。 如果此Map先前包含此键的映射,则旧值将替换为指定的值。

5 size()

返回此Map中键 - 值映射的数量。

6 values()

返回此Map中包含的值的集合视图。

Groovy - Dates & Times

Date类表示特定的时刻,精度为毫秒。 Date类有两个构造函数,如下所示。

Date()

语法 (Syntax)

public Date()

Parameters - 无。

Return Value

分配一个Date对象并对其进行初始化,使其表示分配时间,测量精确到毫秒。

例子 (Example)

以下是此方法的使用示例 -

class Example { 
   static void main(String[] args) { 
      Date date = new Date(); 
      // display time and date using toString() 
      System.out.println(date.toString()); 
   } 
} 

当我们运行上述程序时,我们将得到以下结果。 以下输出将为您提供当前日期和时间 -

Thu Dec 10 21:31:15 GST 2015

Date (long millisec)

语法 (Syntax)

public Date(long millisec)

Parameters

Millisec - 自标准基准时间以来指定的毫秒数。

Return Value - 分配Date对象并将其初始化以表示自标准基准时间(称为“epoch”)以来的指定毫秒数,即1970年1月1日00:00:00 GMT。

例子 (Example)

以下是此方法的使用示例 -

class Example {
   static void main(String[] args) {
      Date date = new Date(100);
      // display time and date using toString()
      System.out.println(date.toString());
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

Thu Jan 01 04:00:00 GST 1970

以下是Date类的给定方法。 在接受或返回年,月,日,小时,分钟和秒值的所有Date类方法中,使用以下表示 -

  • 年y由整数y - 1900表示。

  • 一个月由0到11的整数表示; 0是1月,1是2月,依此类推; 因此11月是12月。

  • 日期(月中的某天)以通常的方式由1到31的整数表示。

  • 小时由0到23之间的整数表示。因此,从午夜到凌晨1点的小时是小时0,从中午到下午1点的小时是小时12。

  • 一分钟由通常方式的0到59的整数表示。

  • 第二个由0到61的整数表示。

Sr.No. 方法和描述
1 after()

测试此日期是否在指定日期之后。

2 equals()

比较两个相等的日期。 当且仅当参数不为null并且是一个Date对象时,结果才为真,该对象表示与此对象相同的时间点,以毫秒为单位。

3 compareTo()

比较两个日期的订购。

4 toString()

将此Date对象转换为String

5 before()

测试此日期是否在指定日期之前。

6 getTime()

返回自此Date对象表示的1970年1月1日00:00:00 GMT以来的毫秒数。

7 setTime()

将此Date对象设置为表示1970年1月1日00:00:00 GMT之后的时间毫秒的时间点。

Groovy - Regular Expressions

正则表达式是用于在文本中查找子字符串的模式。 Groovy本身使用〜“regex”表达式支持正则表达式。 引号中的文字代表比较的表达。

例如,我们可以创建一个正则表达式对象,如下所示 -

def regex = ~'Groovy'

当Groovy运算符=〜在ifwhile语句中显示为谓词(表达式返回布尔值) while (参见第8章),左侧的String操作数与右侧的正则表达式操作数匹配。 因此,以下每个都赋予真值。

定义正则表达式时,可以使用以下特殊字符 -

  • 有两个特殊的位置字符用于表示一行的开头和结尾:插入符号(∧)和美元符号($)。

  • 正则表达式还可以包括量词。 加号(+)表示一次或多次,应用于表达式的前一个元素。 星号(*)用于表示零次或多次出现。 问号(?)表示零或一次。

  • 元字符{和}用于匹配前一个字符的特定数量的实例。

  • 在正则表达式中,句点符号(。)可以表示任何字符。 这被描述为通配符。

  • 正则表达式可以包括字符类。 一组字符可以作为包含在元字符[和]中的简单字符序列给出,如[aeiou]中所示。 对于字母或数字范围,您可以使用[a-z]或[a-mA-M]中的短划线分隔符。 字符类的补码由方形球拍内的前导插入符号表示,如[∧a-z]中所示,表示除指定之外的所有字符。 下面给出了正则表达式的一些示例

'Groovy' =~ 'Groovy' 
'Groovy' =~ 'oo' 
'Groovy' ==~ 'Groovy' 
'Groovy' ==~ 'oo' 
'Groovy' =~ '∧G' 
‘Groovy' =~ 'G$' 
‘Groovy' =~ 'Gro*vy' 'Groovy' =~ 'Gro{2}vy'

Groovy - Exception Handling

任何编程语言都需要异常处理来处理运行时错误,以便可以保持应用程序的正常流程。

异常通常会破坏应用程序的正常流程,这就是我们需要在应用程序中使用异常处理的原因。

例外大致分为以下几类 -

  • Checked Exception - 除RuntimeException和Error之外的扩展Throwable类的类称为已检查的异常egIOException,SQLException等。在编译时检查已检查的异常。

一个经典案例是FileNotFoundException。 假设您的应用程序中有以下代码,它从E盘中的文件中读取。

class Example {
   static void main(String[] args) {
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file);
   } 
}

如果E驱动器中没有File(file.txt),则会引发以下异常。

抓到:java.io.FileNotFoundException:E:\file.txt(系统找不到指定的文件)。

java.io.FileNotFoundException:E:\file.txt(系统找不到指定的文件)。

  • Unchecked Exception - 扩展RuntimeException的类称为未经检查的异常,例如,ArithmeticException,NullPointerException,ArrayIndexOutOfBoundsException等。未在编译时检查未经检查的异常,而不是在运行时检查它们。

一个经典案例是ArrayIndexOutOfBoundsException,当您尝试访问大于数组长度的数组索引时会发生这种情况。 以下是此类错误的典型示例。

class Example {
   static void main(String[] args) {
      def arr = new int[3];
      arr[5] = 5;
   } 
}

执行上述代码时,将引发以下异常。

抓到:java.lang.ArrayIndexOutOfBoundsException:5

java.lang.ArrayIndexOutOfBoundsException:5

  • Error - 错误无法恢复,例如OutOfMemoryError,VirtualMachineError,AssertionError等。

这些是程序永远无法恢复的错误,并且会导致程序崩溃。

下图显示了如何组织Groovy中的异常层次结构。 它都基于Java中定义的层次结构。

异常层次结构

捕捉异常

方法使用trycatch关键字的组合捕获异常。 try/catch块放在可能生成异常的代码周围。

try { 
   //Protected code 
} catch(ExceptionName e1) {
   //Catch block 
}

您可能引发异常的所有代码都放在受保护的代码块中。

在catch块中,您可以编写自定义代码来处理异常,以便应用程序可以从异常中恢复。

让我们看一下上面看到的类似代码的示例,这些代码用于访问索引值大于数组大小的数组。 但是这一次让我们将代码包装在try/catch块中。

class Example {
   static void main(String[] args) {
      try {
         def arr = new int[3];
         arr[5] = 5;
      } catch(Exception ex) {
         println("Catching the exception");
      }
      println("Let's move on after the exception");
   }
}

当我们运行上述程序时,我们将得到以下结果 -

Catching the exception 
Let's move on after the exception

从上面的代码中,我们在try块中包含了错误的代码。 在catch块中,我们只是捕获异常并输出发生异常的消息。

多个捕获块

可以有多个catch块来处理多种类型的异常。 对于每个catch块,根据引发的异常类型,您将编写代码来相应地处理它。

让我们修改上面的代码来专门捕获ArrayIndexOutOfBoundsException。 以下是代码段。

class Example {
   static void main(String[] args) {
      try {
         def arr = new int[3];
         arr[5] = 5;
      }catch(ArrayIndexOutOfBoundsException ex) {
         println("Catching the Array out of Bounds exception");
      }catch(Exception ex) {
         println("Catching the exception");
      }
      println("Let's move on after the exception");
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

Catching the Aray out of Bounds exception 
Let's move on after the exception

从上面的代码可以看出,首先捕获了ArrayIndexOutOfBoundsException catch块,因为它意味着异常的标准。

最后座

finally块遵循try块或catch块。 无论发生异常,最终都会执行最后一段代码。

使用finally块允许您运行要执行的任何清理类型语句,无论受保护代码中发生什么。 该块的语法如下。

try { 
   //Protected code 
} catch(ExceptionType1 e1) { 
   //Catch block 
} catch(ExceptionType2 e2) { 
   //Catch block 
} catch(ExceptionType3 e3) { 
   //Catch block 
} finally {
   //The finally block always executes. 
}

让我们修改上面的代码并添加finally代码块。 以下是代码段。

class Example {
   static void main(String[] args) {
      try {
         def arr = new int[3];
         arr[5] = 5;
      } catch(ArrayIndexOutOfBoundsException ex) {
         println("Catching the Array out of Bounds exception");
      }catch(Exception ex) {
         println("Catching the exception");
      } finally {
         println("The final block");
      }
      println("Let's move on after the exception");
   } 
} 

当我们运行上述程序时,我们将得到以下结果 -

Catching the Array out of Bounds exception 
The final block 
Let's move on after the exception

以下是Groovy中可用的异常方法 -

public String getMessage()

返回有关已发生的异常的详细消息。 此消息在Throwable构造函数中初始化。

public Throwable getCause()

返回由Throwable对象表示的异常的原因。

public String toString()

返回与getMessage()结果连接的类的名称

public void printStackTrace()

将toString()的结果与堆栈跟踪一起打印到System.err(错误输出流)。

public StackTraceElement [] getStackTrace()

返回包含堆栈跟踪上每个元素的数组。 索引0处的元素表示调用堆栈的顶部,而数组中的最后一个元素表示调用堆栈底部的方法。

public Throwable fillInStackTrace()

使用当前堆栈跟踪填充此Throwable对象的堆栈跟踪,添加堆栈跟踪中的任何先前信息。

例子 (Example)

以下是使用上面给出的一些方法的代码示例 -

class Example {
   static void main(String[] args) {
      try {
         def arr = new int[3];
         arr[5] = 5;
      }catch(ArrayIndexOutOfBoundsException ex) {
         println(ex.toString());
         println(ex.getMessage());
         println(ex.getStackTrace());  
      } catch(Exception ex) {
         println("Catching the exception");
      }finally {
         println("The final block");
      }
      println("Let's move on after the exception");
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

java.lang.ArrayIndexOutOfBoundsException: 5 
5 
[org.codehaus.groovy.runtime.dgmimpl.arrays.IntegerArrayPutAtMetaMethod$MyPojoMetaMet 
hodSite.call(IntegerArrayPutAtMetaMethod.java:75), 
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) ,
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) ,
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133) ,
Example.main(Sample:8), sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
java.lang.reflect.Method.invoke(Method.java:606),
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93),
groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325),
groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1443),
org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:893),
groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:287),
groovy.lang.GroovyShell.run(GroovyShell.java:524),
groovy.lang.GroovyShell.run(GroovyShell.java:513),
groovy.ui.GroovyMain.processOnce(GroovyMain.java:652),
groovy.ui.GroovyMain.run(GroovyMain.java:384),
groovy.ui.GroovyMain.process(GroovyMain.java:370),
groovy.ui.GroovyMain.processArgs(GroovyMain.java:129),
groovy.ui.GroovyMain.main(GroovyMain.java:109),
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
java.lang.reflect.Method.invoke(Method.java:606),
org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109),
org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131),
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
java.lang.reflect.Method.invoke(Method.java:606),
com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)]
The final block 
Let's move on after the exception 

Groovy - Object Oriented

在Groovy中,与任何其他面向对象语言一样,有类和对象的概念来表示编程语言的面向对象性质。 Groovy类是数据的集合以及对该数据进行操作的方法。 同时,类的数据和方法用于表示来自问题域的一些现实世界对象。

Groovy中的类声明状态(数据)和该类定义的对象的行为。 因此,Groovy类描述了该类的实例字段和方法。

以下是Groovy中的类的示例。 该类的名称是Student,它有两个字段 - StudentIDStudentName 。 在main函数中,我们创建了此类的对象,并将值分配给对象的StudentIDStudentName

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);
      st.setStudentName("Joe");
      println(st.getStudentID());
      println(st.getStudentName());
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

1 
Joe 

请注意以下有关上述计划的要点 -

  • 在类中,studentID和studentName都标记为private,这意味着无法从类外部访问它们。

  • 每个实例成员都有自己的getter和setter方法。 getter方法返回实例变量的值,例如方法int getStudentID()和setter方法设置实例ID的值,例如方法 - void setStudentName(String pName)

实例方法

在类中包含更多方法通常是很自然的,这些方法实际上为类提供了某种功能。 在我们的学生示例中,让我们添加Marks1,Marks2和Marks3的实例成员来表示3个科目中学生的分数。 然后,我们将添加一个新的实例方法,该方法将计算学生的总分。 以下是代码的外观。

在下面的示例中,方法Total是一个附加的Instance方法,它内置了一些逻辑。

class Student {
   int StudentID;
   String StudentName;
   int Marks1;
   int Marks2;
   int Marks3;
   int Total() {
      return Marks1+Marks2+Marks3;
   }
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.StudentName="Joe";
      st.Marks1 = 10;
      st.Marks2 = 20;
      st.Marks3 = 30;
      println(st.Total());
   }
}

当我们运行上述程序时,我们将得到以下结果 -

60

创建多个对象

人们还可以创建一个类的多个对象。 以下是如何实现这一目标的示例。 在这里,我们创建了3个对象(st,st1和st2)并相应地调用它们的实例成员和实例方法。

class Student {
   int StudentID;
   String StudentName;
   int Marks1;
   int Marks2;
   int Marks3;
   int Total() { 
      return Marks1+Marks2+Marks3;
   } 
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.StudentName = "Joe";
      st.Marks1 = 10;
      st.Marks2 = 20;
      st.Marks3 = 30;
      println(st.Total()); 
      Student st1 = new Student();
      st.StudentID = 1;
      st.StudentName = "Joe";
      st.Marks1 = 10;
      st.Marks2 = 20;
      st.Marks3 = 40;
      println(st.Total());  
      Student st3 = new Student();
      st.StudentID = 1;
      st.StudentName = "Joe";
      st.Marks1 = 10; 
      st.Marks2 = 20;
      st.Marks3 = 50;
      println(st.Total());
   } 
} 

当我们运行上述程序时,我们将得到以下结果 -

60 
70 
80 

继承 (Inheritance)

继承可以定义为一个类获取另一个类的属性(方法和字段)的过程。 通过使用继承,可以按层次顺序管理信息。

继承其他属性的类称为子类(派生类,子类),其属性被继承的类称为超类(基类,父类)。

Extends

extends是用于继承类属性的关键字。 下面给出的是extends关键字的语法。 在以下示例中,我们正在执行以下操作 -

  • 创建一个名为Person的类。 该类有一个名为name的实例成员。

  • 创建一个名为Student的类,它从Person类扩展而来。 请注意,Person类中定义的名称实例成员将在Student类中继承。

  • 在Student类构造函数中,我们调用基类构造函数。

  • 在我们的Student类中,我们添加了另外两个StudentID和Marks1的实例成员。

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.Marks1 = 10;
      st.name = "Joe";
      println(st.name);
   }
} 
class Person {
   public String name;
   public Person() {}  
} 
class Student extends Person {
   int StudentID
   int Marks1;
   public Student() {
      super();
   } 
}   

当我们运行上述程序时,我们将得到以下结果 -

Joe

内在的类

内部类在另一个类中定义。 封闭类可以像往常一样使用内部类。 另一方面,内部类可以访问其封闭类的成员,即使它们是私有的。 封闭类以外的类不允许访问内部类。

以下是外部和内部类的示例。 在以下示例中,我们正在执行以下操作 -

  • 创建一个名为Outer的类,它将成为我们的外部类。
  • 在我们的Outer类中定义一个名为name的字符串。
  • 在我们的Outer类中创建一个Inner或嵌套类。
  • 请注意,在内部类中,我们能够访问在Outer类中定义的名称实例成员。
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); 
      } 
   } 
}   

当我们运行上述程序时,我们将得到以下结果 -

Joe

抽象类

抽象类表示通用概念,因此,它们无法实例化,被创建为子类。 他们的成员包括字段/属性和抽象或具体方法。 抽象方法没有实现,必须由具体的子类实现。 必须使用abstract关键字声明抽象类。 抽象方法也必须使用abstract关键字声明。

在下面的示例中,请注意Person类现在变为抽象类,无法实例化。 另请注意,抽象类中有一个名为DisplayMarks的抽象方法,它没有实现细节。 在学生班中,必须添加实施细节。

class Example { 
   static void main(String[] args) { 
      Student st = new Student(); 
      st.StudentID = 1;
      st.Marks1 = 10; 
      st.name="Joe"; 
      println(st.name); 
      println(st.DisplayMarks()); 
   } 
} 
abstract class Person { 
   public String name; 
   public Person() { } 
   abstract void DisplayMarks();
}
class Student extends Person { 
   int StudentID 
   int Marks1; 
   public Student() { 
      super(); 
   } 
   void DisplayMarks() { 
      println(Marks1); 
   }  
} 

当我们运行上述程序时,我们将得到以下结果 -

Joe 
10 
null

Interfaces

接口定义了类需要遵循的契约。 接口仅定义需要实现的方法列表,但不定义方法实现。 需要使用interface关键字声明接口。 接口仅定义方法签名。 接口的方法总是public 。 在接口中使用受保护或私有方法是错误的。

以下是groovy中的接口示例。 在以下示例中,我们正在执行以下操作 -

  • 创建一个名为Marks的接口,并创建一个名为DisplayMarks的接口方法。

  • 在类定义中,我们使用implements关键字来实现接口。

  • 因为我们正在实现接口,所以我们必须为DisplayMarks方法提供实现。

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

当我们运行上述程序时,我们将得到以下结果 -

10
null

Groovy - Generics

泛型使类型(类和接口)在定义类,接口和方法时成为参数。 与方法声明中使用的更熟悉的形式参数非常相似,类型参数为您提供了一种使用不同输入重用相同代码的方法。 不同之处在于形式参数的输入是值,而类型参数的输入是类型。

集合的通用

可以对诸如List类之类的集合类进行通用化,以便在应用程序中仅接受该类型的集合。 广义ArrayList的示例如下所示。 以下语句的作用是它只接受字符串类型的列表项 -

List<String> list = new ArrayList<String>();

在下面的代码示例中,我们正在执行以下操作 -

  • 创建一个只包含字符串的通用ArrayList集合。
  • 在列表中添加3个字符串。
  • 对于列表中的每个项目,打印字符串的值。
class Example {
   static void main(String[] args) {
      // Creating a generic List collection
      List<String> list = new ArrayList<String>();
      list.add("First String");
      list.add("Second String");
      list.add("Third String");
      for(String str : list) {
         println(str);
      }
   } 
}

上述计划的输出将是 -

First String 
Second String 
Third String

广义类

整个class也可以推广。 这使得类更灵活地接受任何类型并相应地使用这些类型。 让我们看看如何实现这一目标的一个例子。

在以下计划中,我们正在执行以下步骤 -

  • 我们正在创建一个名为ListType的类。 请注意放在类定义前面的关键字。 这告诉编译器该类可以接受任何类型。 因此,当我们声明此类的对象时,我们可以在声明期间指定一个类型,并且该类型将在占位符中替换

  • 泛型类具有简单的getter和setter方法,可以使用类中定义的成员变量。

  • 在主程序中,请注意我们能够声明ListType类的对象,但是具有不同类型的对象。 第一个是Integer类型,第二个是String类型。

class Example {
   static void main(String[] args) {
      // Creating a generic List collection 
      ListType<String> lststr = new ListType<>();
      lststr.set("First String");
      println(lststr.get()); 
      ListType<Integer> lstint = new ListType<>();
      lstint.set(1);
      println(lstint.get());
   }
} 
public class ListType<T> {
   private T localt;
   public T get() {
      return this.localt;
   }
   public void set(T plocal) {
      this.localt = plocal;
   } 
}

上述计划的输出将是 -

First String 
1

Groovy - Traits

特征是语言的结构构造,允许 -

  • Composition of behaviors.
  • 接口的运行时实现。
  • 与静态类型检查/编译的兼容性

它们可以被视为承载默认实现和状态的接口。 使用trait关键字定义特征。

下面给出了一个特征的例子 -

trait Marks {
   void DisplayMarks() {
      println("Display Marks");
   } 
}

然后可以使用implement关键字以与接口类似的方式实现特征。

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

实现接口

Traits可以实现接口,在这种情况下,接口是使用implements关键字声明的。

下面给出了实现接口的特征的示例。 在以下示例中,可以注意以下关键点。

  • 使用DisplayTotal方法定义接口Total。

  • 特征Marks实现了Total接口,因此需要为DisplayTotal方法提供实现。

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.Marks1 = 10;
      println(st.DisplayMarks());
      println(st.DisplayTotal());
   } 
} 
interface Total {
   void DisplayTotal() 
} 
trait Marks implements Total {
   void DisplayMarks() {
      println("Display Marks");
   }
   void DisplayTotal() {
      println("Display Total"); 
   } 
} 
class Student implements Marks { 
   int StudentID
   int Marks1;  
} 

上述计划的输出将是 -

Display Marks 
Display Total

属性 Properties

特征可以定义属性。 下面给出了具有财产的特征的示例。

在以下示例中,integer类型的Marks1是一个属性。

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      println(st.DisplayMarks());
      println(st.DisplayTotal());
   } 
   interface Total {
      void DisplayTotal() 
   } 
   trait Marks implements Total {
      int Marks1;
      void DisplayMarks() {
         this.Marks1 = 10;
         println(this.Marks1);
      }
      void DisplayTotal() {
         println("Display Total");
      } 
   } 
   class Student implements Marks {
      int StudentID 
   }
} 

上述计划的输出将是 -

10 
Display Total

行为的构成

特征可用于以受控方式实现多重继承,从而避免钻石问题。 在下面的代码示例中,我们定义了两个特征 - MarksTotal 。 我们的Student类实现了两个特征。 由于学生类扩展了两个特征,因此可以访问两种方法 - DisplayMarksDisplayTotal

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      println(st.DisplayMarks());
      println(st.DisplayTotal()); 
   } 
} 
trait Marks {
   void DisplayMarks() {
      println("Marks1");
   } 
} 
trait Total {
   void DisplayTotal() { 
      println("Total");
   } 
}  
class Student implements Marks,Total {
   int StudentID 
}   

上述计划的输出将是 -

Total 
Marks1

延伸特征

特征可以扩展另一个特征,在这种情况下,您必须使用extends关键字。 在下面的代码示例中,我们使用Marks trait扩展Total trait。

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      println(st.DisplayMarks());
   } 
} 
trait Marks {
   void DisplayMarks() {
      println("Marks1");
   } 
} 
trait Total extends Marks {
   void DisplayMarks() {
      println("Total");
   } 
}  
class Student implements Total {
   int StudentID 
}

上述计划的输出将是 -

Total

Groovy - Closures

闭包是一个简短的匿名代码块。 它通常只包含几行代码。 方法甚至可以将代码块作为参数。 他们本质上是匿名的。

以下是一个简单闭包的例子,它看起来像什么。

class Example {
   static void main(String[] args) {
      def clos = {println "Hello World"};
      clos.call();
   } 
}

在上面的例子中,代码行 - {println“Hello World”}被称为闭包。 可以使用call语句执行此标识符引用的代码块。

当我们运行上述程序时,我们将得到以下结果 -

Hello World

闭包中的形式参数

闭包还可以包含形式参数,以使它们像Groovy中的方法一样更有用。

class Example {
   static void main(String[] args) {
      def clos = {param->println "Hello ${param}"};
      clos.call("World");
   } 
}

在上面的代码示例中,请注意$ {param}的使用,这会导致闭包获取参数。 通过clos.call语句调用闭包时,我们现在可以选择将参数传递给闭包。

当我们运行上述程序时,我们将得到以下结果 -

Hello World

下一个插图重复前一个示例并生成相同的结果,但显示可以使用称为它的隐式单个参数。 这里'它'是Groovy中的关键字。

class Example {
   static void main(String[] args) {
      def clos = {println "Hello ${it}"};
      clos.call("World");
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

Hello World

闭包和变量

更正式地说,闭包可以在定义闭包时引用变量。 以下是如何实现这一目标的示例。

class Example {     
   static void main(String[] args) {
      def str1 = "Hello";
      def clos = {param -> println "${str1} ${param}"}
      clos.call("World");
      // We are now changing the value of the String str1 which is referenced in the closure
      str1 = "Welcome";
      clos.call("World");
   } 
}

在上面的例子中,除了将参数传递给闭包之外,我们还定义了一个名为str1的变量。 闭包还带有变量和参数。

当我们运行上述程序时,我们将得到以下结果 -

Hello World 
Welcome World

在方法中使用闭包

闭包也可以用作方法的参数。 在Groovy中,许多内置的数据类型方法(如列表和集合)都将闭包作为参数类型。

以下示例显示如何将闭包作为参数发送到方法。

class Example { 
   def static Display(clo) {
      // This time the $param parameter gets replaced by the string "Inner"         
      clo.call("Inner");
   } 
   static void main(String[] args) {
      def str1 = "Hello";
      def clos = { param -> println "${str1} ${param}" }
      clos.call("World");
      // We are now changing the value of the String str1 which is referenced in the closure
      str1 = "Welcome";
      clos.call("World");
      // Passing our closure to a method
      Example.Display(clos);
   } 
}

在上面的例子中,

  • 我们定义了一个名为Display的静态方法,它将闭包作为参数。

  • 然后我们在main方法中定义一个闭包,并将它作为参数传递给Display方法。

当我们运行上述程序时,我们将得到以下结果 -

Hello World 
Welcome World 
Welcome Inner

集合和字符串中的闭包

几个List,Map和String方法接受闭包作为参数。 让我们看一下如何在这些数据类型中使用闭包的示例。

使用带有列表的闭包

以下示例显示了如何将闭包与列表一起使用。 在下面的示例中,我们首先定义一个简单的值列表。 然后列表集合类型定义一个名为的函数。 each 。 此函数将闭包作为参数,并将闭包应用于列表的每个元素。

class Example {
   static void main(String[] args) {
      def lst = [11, 12, 13, 14];
      lst.each {println it}
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

11 
12 
13 
14

使用带有地图的闭包

以下示例显示了如何将闭包与Maps一起使用。 在下面的示例中,我们首先定义一个简单的键值项映射。 然后,地图集合类型定义了一个名为.each的函数。 此函数将闭包作为参数,并将闭包应用于映射的每个键值对。

class Example {
   static void main(String[] args) {
      def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]             
      mp.each {println it}
      mp.each {println "${it.key} maps to: ${it.value}"}
   } 
}

当我们运行上述程序时,我们将得到以下结果 -

TopicName = Maps 
TopicDescription = Methods in Maps 
TopicName maps to: Maps 
TopicDescription maps to: Methods in Maps

通常,我们可能希望迭代集合的成员并仅在元素满足某些标准时应用某些逻辑。 这可以通过闭包中的条件语句来处理。

class Example {
   static void main(String[] args) {
      def lst = [1,2,3,4];
      lst.each {println it}
      println("The list will only display those numbers which are divisible by 2")
      lst.each{num -> if(num % 2 == 0) println num}
   } 
}

上面的示例显示了闭包中使用的条件if(num%2 == 0)表达式,用于检查列表中的每个项目是否可被2整除。

当我们运行上述程序时,我们将得到以下结果 -

1 
2 
3 
4 
The list will only display those numbers which are divisible by 2.
2 
4 

与闭包一起使用的方法

闭包本身提供了一些方法。

Sr.No. 方法和描述
1 find()

find方法在集合中查找与某个条件匹配的第一个值。

2 findAll()

它查找接收对象中与闭包条件匹配的所有值。

3 any()&every()

方法any遍历集合的每个元素,检查布尔谓词是否对至少一个元素有效。

4 collect()

方法collect遍历集合,使用闭包作为变换器将每个元素转换为新值。

Groovy - Annotations

Annotations是元数据的一种形式,其中它们提供关于不是程序本身的一部分的程序的数据。 注释对它们注释的代码的操作没有直接影响。

注释主要用于以下原因 -

  • Information for the compiler - Information for the compiler可以使用注释来检测错误或抑制警告。

  • Compile-time and deployment-time processing - 软件工具可以处理注释信息以生成代码,XML文件等。

  • Runtime processing - 可以在运行时检查某些注释。

在Groovy中,基本注释如下所示 -

@interface - 符号字符(@)向编译器指示后面的内容是注释。

注释可以the form没有实体和可选默认值的方法the form定义成员。

注释可以应用于以下类型 -

字符串类型

下面给出了字符串注释的示例 -

@interface Simple { 
   String str1() default "HelloWorld"; 
}

枚举类型

enum DayOfWeek { mon, tue, wed, thu, fri, sat, sun } 
@interface Scheduled {
   DayOfWeek dayOfWeek() 
} 

class类型

@interface Simple {} 
@Simple 
class User {
   String username
   int age
}
def user = new User(username: "Joe",age:1); 
println(user.age); 
println(user.username);

注释成员值

使用注释时,至少需要设置所有没有默认值的成员。 下面给出一个例子。 在定义后使用注释示例时,需要为其分配值。

@interface Example {
   int status() 
}
@Example(status = 1)

闭包注释参数

Groovy中注释的一个很好的特性是你也可以使用闭包作为注释值。 因此,注释可以与各种表达一起使用。

下面给出一个例子。 注释Onlyif是基于类值创建的。 然后将注释应用于两个方法,这两个方法根据数字变量的值将不同的消息发布到结果变量。

@interface OnlyIf {
   Class value() 
}  
@OnlyIf({ number<=6 }) 
void Version6() {
   result << 'Number greater than 6' 
} 
@OnlyIf({ number>=6 }) 
void Version7() {
   result << 'Number greater than 6' 
}

元注释

这是groovy中注释的一个非常有用的功能。 有时可能会有一个方法的多个注释,如下所示。 有时,如果有多个注释,这可能会变得混乱。

@Procedure 
@Master class 
MyMasterProcedure {} 

在这种情况下,您可以定义一个元注释,它将多个注释结合在一起,并将元注释应用于该方法。 因此,对于上面的示例,您可以使用AnnotationCollector定义注释集合。

import groovy.transform.AnnotationCollector
@Procedure 
@Master 
@AnnotationCollector

完成此操作后,您可以将以下元注释器应用于该方法 -

import groovy.transform.AnnotationCollector
@Procedure 
@Master 
@AnnotationCollector
@MasterProcedure 
class MyMasterProcedure {}

Groovy - XML

XML是一种可移植的开源语言,它允许程序员开发可由其他应用程序读取的应用程序,而不管操作系统和/或开发语言如何。 这是用于在应用程序之间交换数据的最常用语言之一。

XML是什么 (What is XML?)/h2>

可扩展标记语言XML是一种非常类似于HTML或SGML的标记语言。 这是万维网联盟推荐的,可作为开放标准提供。 XML对于跟踪中小数据量非常有用,而不需要基于SQL的主干。

Groovy中的XML支持

Groovy语言还提供了对XML语言的丰富支持。 使用的两个最基本的XML类是 -

  • XML Markup Builder - Groovy支持基于树的标记生成器BuilderSupport,它可以被子类化以生成各种树形结构的对象表示。 通常,这些构建器用于表示XML标记,HTML标记。 Groovy的标记生成器捕获对伪方法的调用并将它们转换为树结构的元素或节点。 这些伪方法的参数被视为节点的属性。 作为方法调用的一部分的闭包被视为结果树节点的嵌套子内容。

  • XML Parser - Groovy XmlParser类使用一个简单的模型将XML文档解析为Node实例树。 每个节点都具有XML元素的名称,元素的属性以及对任何子节点的引用。 此模型足以进行大多数简单的XML处理。

对于我们所有的XML代码示例,让我们使用以下简单的XML文件movies.xml来构建XML文件并随后读取该文件。

<collection shelf = "New Arrivals"> 
   <movie title = "Enemy Behind"> 
      <type>War, Thriller</type> 
      <format>DVD</format> 
      <year>2003</year> 
      <rating>PG</rating> 
      <stars>10</stars> 
      <description>Talk about a US-Japan war</description> 
   </movie> 
   <movie title = "Transformers"> 
      <type>Anime, Science Fiction</type>
      <format>DVD</format> 
      <year>1989</year> 
      <rating>R</rating> 
      <stars>8</stars> 
      <description>A schientific fiction</description> 
   </movie> 
   <movie title = "Trigun"> 
      <type>Anime, Action</type> 
      <format>DVD</format> 
      <year>1986</year> 
      <rating>PG</rating> 
      <stars>10</stars> 
      <description>Vash the Stam pede!</description> 
   </movie> 
   <movie title = "Ishtar"> 
      <type>Comedy</type> 
      <format>VHS</format> 
      <year>1987</year> 
      <rating>PG</rating> 
      <stars>2</stars> 
      <description>Viewable boredom </description> 
   </movie> 
</collection> 

XML标记生成器

语法 (Syntax)

public MarkupBuilder()

MarkupBuilder用于构造整个XML文档。 首先创建XML文档类的对象来创建XML文档。 创建对象后,可以调用伪方法来创建XML文档的各种元素。

让我们看一个如何创建一个块的示例,即上述XML文档中的一个电影元素 -

import groovy.xml.MarkupBuilder 
class Example {
   static void main(String[] args) {
      def mB = new MarkupBuilder()
      // Compose the builder
      mB.collection(shelf : 'New Arrivals') {
         movie(title : 'Enemy Behind')
         type('War, Thriller')
         format('DVD')
         year('2003')
         rating('PG')
         stars(10)
         description('Talk about a US-Japan war') 
      }
   } 
}

在上面的例子中,需要注意以下事项 -

  • mB.collection() - 这是一个标记生成器,它创建“collection”“/ collection”的头部XML标记

  • movie(title : 'Enemy Behind') - 这些伪方法使用此方法创建子标记,并使用值创建标记。 通过指定名为title的值,这实际上表明需要为元素创建属性。

  • 为伪方法提供了一个闭包,以创建XML文档的其余元素。

  • 初始化类MarkupBuilder的默认构造函数,以便将生成的XML发布到标准输出流

当我们运行上述程序时,我们将得到以下结果 -

<collection shelf = 'New Arrivals'> 
   <movie title = 'Enemy Behind' /> 
      <type>War, Thriller</type> 
      <format>DVD</format> 
      <year>2003</year> 
      <rating>PG</rating> 
      <stars>10</stars> 
      <description>Talk about a US-Japan war</description> 
   </movie> 
</collection>

为了创建整个XML文档,需要完成以下事项。

  • 需要创建映射条目以存储元素的不同值。
  • 对于地图的每个元素,我们将值分配给每个元素。
import groovy.xml.MarkupBuilder 
class Example {
   static void main(String[] args) {
      def mp = [1 : ['Enemy Behind', 'War, Thriller','DVD','2003', 
         'PG', '10','Talk about a US-Japan war'],
         2 : ['Transformers','Anime, Science Fiction','DVD','1989', 
         'R', '8','A scientific fiction'],
         3 : ['Trigun','Anime, Action','DVD','1986', 
         'PG', '10','Vash the Stam pede'],
         4 : ['Ishtar','Comedy','VHS','1987', 'PG', 
         '2','Viewable boredom ']] 
      def mB = new MarkupBuilder()  
      // Compose the builder
      def MOVIEDB = mB.collection('shelf': 'New Arrivals') {
         mp.each {
            sd -> 
            mB.movie('title': sd.value[0]) {  
               type(sd.value[1])
               format(sd.value[2])
               year(sd.value[3]) 
               rating(sd.value[4])
               stars(sd.value[4]) 
               description(sd.value[5]) 
            }
         }
      }
   } 
} 

当我们运行上述程序时,我们将得到以下结果 -

<collection shelf = 'New Arrivals'> 
   <movie title = 'Enemy Behind'> 
      <type>War, Thriller</type> 
      <format>DVD</format> 
      <year>2003</year> 
      <rating>PG</rating> 
      <stars>PG</stars> 
      <description>10</description> 
   </movie> 
   <movie title = 'Transformers'> 
      <type>Anime, Science Fiction</type> 
      <format>DVD</format> 
      <year>1989</year>
	  <rating>R</rating> 
      <stars>R</stars> 
      <description>8</description> 
   </movie> 
   <movie title = 'Trigun'> 
      <type>Anime, Action</type> 
      <format>DVD</format> 
      <year>1986</year> 
      <rating>PG</rating> 
      <stars>PG</stars> 
      <description>10</description> 
   </movie> 
   <movie title = 'Ishtar'> 
      <type>Comedy</type> 
      <format>VHS</format> 
      <year>1987</year> 
      <rating>PG</rating> 
      <stars>PG</stars> 
      <description>2</description> 
   </movie> 
</collection> 

XML解析

Groovy XmlParser类使用一个简单的模型将XML文档解析为Node实例树。 每个节点都具有XML元素的名称,元素的属性以及对任何子节点的引用。 此模型足以进行大多数简单的XML处理。

语法 (Syntax)

public XmlParser() 
   throws ParserConfigurationException, 
      SAXException

以下代码显示了如何使用XML解析器读取XML文档的示例。

假设我们有相同的文档名为Movies.xml,我们想要解析XML文档并向用户显示正确的输出。 以下代码是我们如何遍历XML文档的整个内容并向用户显示正确响应的片段。

import groovy.xml.MarkupBuilder 
import groovy.util.*
class Example {
   static void main(String[] args) { 
      def parser = new XmlParser()
      def doc = parser.parse("D:\\Movies.xml");
      doc.movie.each{
         bk->
         print("Movie Name:")
         println "${bk['@title']}"
         print("Movie Type:")
         println "${bk.type[0].text()}"
         print("Movie Format:")
         println "${bk.format[0].text()}"
         print("Movie year:")
         println "${bk.year[0].text()}"
         print("Movie rating:")
         println "${bk.rating[0].text()}"
         print("Movie stars:")
         println "${bk.stars[0].text()}"
         print("Movie description:")
         println "${bk.description[0].text()}"
         println("*******************************")
      }
   }
} 

当我们运行上述程序时,我们将得到以下结果 -

Movie Name:Enemy Behind 
Movie Type:War, Thriller 
Movie Format:DVD 
Movie year:2003 
Movie rating:PG 
Movie stars:10 
Movie description:Talk about a US-Japan war 
******************************* 
Movie Name:Transformers 
Movie Type:Anime, Science Fiction 
Movie Format:DVD 
Movie year:1989 
Movie rating:R 
Movie stars:8 
Movie description:A schientific fiction 
******************************* 
Movie Name:Trigun 
Movie Type:Anime, Action
Movie Format:DVD 
Movie year:1986 
Movie rating:PG 
Movie stars:10 
Movie description:Vash the Stam pede! 
******************************* 
Movie Name:Ishtar 
Movie Type:Comedy 
Movie Format:VHS 
Movie year:1987 
Movie rating:PG 
Movie stars:2 
Movie description:Viewable boredom

有关上述代码的重要注意事项。

  • 正在形成类XmlParser的对象,以便它可用于解析XML文档。

  • 解析器被赋予XML文件的位置。

  • 对于每个影片元素,我们使用闭包来浏览每个子节点并显示相关信息。

对于movie元素本身,我们使用@符号显示附加到movie元素的title属性。

Groovy - JMX

JMX是事实上的标准,用于监视与Java虚拟环境有关的所有应用程序。 鉴于Groovy直接位于Java之上,Groovy可以利用已经为JMX和Java完成的大量工作。

监视JVM

可以使用java.lang.management中提供的标准类来执行JVM的监视。 以下代码示例显示了如何完成此操作。

import java.lang.management.*
def os = ManagementFactory.operatingSystemMXBean 
println """OPERATING SYSTEM: 
\tOS architecture = $os.arch 
\tOS name = $os.name 
\tOS version = $os.version 
\tOS processors = $os.availableProcessors 
""" 
def rt = ManagementFactory.runtimeMXBean 
println """RUNTIME: 
   \tRuntime name = $rt.name 
   \tRuntime spec name = $rt.specName 
   \tRuntime vendor = $rt.specVendor 
   \tRuntime spec version = $rt.specVersion 
   \tRuntime management spec version = $rt.managementSpecVersion 
   """ 
def mem = ManagementFactory.memoryMXBean 
def heapUsage = mem.heapMemoryUsage 
def nonHeapUsage = mem.nonHeapMemoryUsage 
println """MEMORY: 
   HEAP STORAGE: 
      \tMemory committed = $heapUsage.committed 
      \tMemory init = $heapUsage.init 
      \tMemory max = $heapUsage.max 
      \tMemory used = $heapUsage.used NON-HEAP STORAGE: 
      \tNon-heap memory committed = $nonHeapUsage.committed 
      \tNon-heap memory init = $nonHeapUsage.init 
      \tNon-heap memory max = $nonHeapUsage.max 
      \tNon-heap memory used = $nonHeapUsage.used 
   """
println "GARBAGE COLLECTION:" 
ManagementFactory.garbageCollectorMXBeans.each { gc ->
   println "\tname = $gc.name"
   println "\t\tcollection count = $gc.collectionCount"
   println "\t\tcollection time = $gc.collectionTime"
   String[] mpoolNames =   gc.memoryPoolNames
   mpoolNames.each { 
      mpoolName -> println "\t\tmpool name = $mpoolName"
   } 
}

执行代码时,输​​出将根据运行代码的系统而有所不同。 下面给出了输出的样本。

OPERATING SYSTEM: 
   OS architecture = x86 
   OS name = Windows 7 
   OS version = 6.1 
   OS processors = 4
RUNTIME: 
   Runtime name = 5144@Babuli-PC 
   Runtime spec name = Java Virtual Machine Specification 
   Runtime vendor = Oracle Corporation 
   Runtime spec version = 1.7 
   Runtime management spec version = 1.2
MEMORY: 
   HEAP STORAGE: 
      Memory committed = 16252928 
      Memory init = 16777216 
      Memory max = 259522560 
      Memory used = 7355840
NON-HEAP STORAGE: 
   Non-heap memory committed = 37715968 
   Non-heap memory init = 35815424 
   Non-heap memory max = 123731968 
   Non-heap memory used = 18532232 
GARBAGE COLLECTION: 
   name = Copy 
   collection count = 15 
   collection time = 47 
   mpool name = Eden Space 
   mpool name = Survivor Space
   name = MarkSweepCompact 
      collection count = 0 
      collection time = 0 
      mpool name = Eden Space 
      mpool name = Survivor Space 
      mpool name = Tenured Gen 
      mpool name = Perm Gen 
      mpool name = Perm Gen [shared-ro] 
      mpool name = Perm Gen [shared-rw]

监控Tomcat

为了监视tomcat,在启动tomcat时应该设置以下参数 -

set JAVA_OPTS = -Dcom.sun.management.jmxremote 
Dcom.sun.management.jmxremote.port = 9004\
-Dcom.sun.management.jmxremote.authenticate=false 
Dcom.sun.management.jmxremote.ssl = false

以下代码使用JMX发现正在运行的Tomcat中的可用MBean,确定哪些是Web模块并提取每个Web模块的处理时间。

import groovy.swing.SwingBuilder
import javax.management.ObjectName 
import javax.management.remote.JMXConnectorFactory as JmxFactory 
import javax.management.remote.JMXServiceURL as JmxUrl 
import javax.swing.WindowConstants as WC 
import org.jfree.chart.ChartFactory 
import org.jfree.data.category.DefaultCategoryDataset as Dataset 
import org.jfree.chart.plot.PlotOrientation as Orientation 
def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi' 
def server = JmxFactory.connect(new JmxUrl(serverUrl)).MBeanServerConnection 
def serverInfo = new GroovyMBean(server, 'Catalina:type = Server').serverInfo 
println "Connected to: $serverInfo" 
def query = new ObjectName('Catalina:*') 
String[] allNames = server.queryNames(query, null) 
def modules = allNames.findAll { name -> 
   name.contains('j2eeType=WebModule') 
}.collect{ new GroovyMBean(server, it) }
println "Found ${modules.size()} web modules. Processing ..." 
def dataset = new Dataset() 
modules.each { m ->
   println m.name()
   dataset.addValue m.processingTime, 0, m.path 
}

Groovy - JSON

本章介绍如何使用Groovy语言解析和生成JSON对象。

JSON函数 (JSON Functions)

Sr.No 功能与图书馆
1

JsonSlurper

JsonSlurper是一个将JSON文本或读者内容解析为Groovy数据的类

结构,如地图,列表和原始类型,如Integer,Double,Boolean和String。

2

JsonOutput

此方法负责将Groovy对象序列化为JSON字符串。

使用JsonSlurper解析数据

JsonSlurper是一个将JSON文本或读者内容解析为Groovy数据结构的类,如地图,列表和基本类型,如Integer,Double,Boolean和String。

语法 (Syntax)

def slurper = new JsonSlurper()

JSON slurper将文本或阅读器内容解析为List and Map的数据结构。

JsonSlurper类为解析器实现提供了几种变体。 有时,在解析某些字符串时,您可能会有不同的要求。 让我们来看一个实例,其中需要读取从Web服务器的响应返回的JSON。 在这种情况下,使用解析器JsonParserLax变体是有益的。 这个parsee允许在JSON文本中注释以及没有引用字符串等。要指定这种解析器,您需要在定义JsonSlurper的对象时使用JsonParserType.LAX解析器类型。

让我们看一下下面给出的一个例子。 该示例用于使用http模块从Web服务器获取JSON数据。 对于这种类型的遍历,最好的选择是将解析器类型设置为JsonParserLax变量。

http.request( GET, TEXT ) {
   headers.Accept = 'application/json'
   headers.'User-Agent' = USER_AGENT
   response.success = { 
      res, rd ->  
      def jsonText = rd.text 
      //Setting the parser type to JsonParserLax
      def parser = new JsonSlurper().setType(JsonParserType.LAX)
      def jsonResp = parser.parseText(jsonText)
   }
}

类似地,Groovy中提供了以下其他解析器类型 -

  • JsonParserCharArray解析器基本上采用JSON字符串并对基础字符数组进行操作。 在值转换期间,它复制字符子阵列(称为“斩波”的机制)并单独对它们进行操作。

  • JsonFastParser是JsonParserCharArray的特殊变体,是最快的解析器。 JsonFastParser也称为索引覆盖解析器。 在解析给定的JSON String期间,它会尽可能地尝试避免创建新的char数组或String实例。 它只保留指向底层原始字符数组的指针。 此外,它尽可能晚地推迟创建对象。

  • JsonParserUsingCharacterSource是一个特殊的解析器,适用于非常大的文件。 它使用一种称为“字符窗口”的技术来解析具有恒定性能特征的大型JSON文件(大型意味着超过2MB大小的文件)。

解析文本

让我们看一下如何使用JsonSlurper类的一些示例。

import groovy.json.JsonSlurper 
class Example {
   static void main(String[] args) {
      def jsonSlurper = new JsonSlurper()
      def object = jsonSlurper.parseText('{ "name": "John", "ID" : "1"}') 
      println(object.name);
      println(object.ID);
   } 
}

在上面的例子中,我们是 -

  • 首先创建一个JsonSlurper类的实例

  • 然后我们使用JsonSlurper类的parseText函数来解析一些JSON文本。

  • 当我们得到对象时,您可以看到我们实际上可以通过密钥访问JSON字符串中的值。

上述计划的输出如下 -

John 
1

解析整数列表

让我们看一下JsonSlurper解析方法的另一个例子。 在下面的示例中,我们正在使用整数列表。 您将从以下代码中注意到我们能够使用每个的List方法并将闭包传递给它。

import groovy.json.JsonSlurper 
class Example {
   static void main(String[] args) {
      def jsonSlurper = new JsonSlurper()
      Object lst = jsonSlurper.parseText('{ "List": [2, 3, 4, 5] }')
      lst.each { println it }
   } 
}

上述计划的输出如下 -

List=[2, 3, 4, 5]

解析原始数据类型列表

JSON解析器还支持string,number,object,true,false和null的原始数据类型。 JsonSlurper类将这些JSON类型转换为相应的Groovy类型。

以下示例显示如何使用JsonSlurper来解析JSON字符串。 在这里,您可以看到JsonSlurper能够将各个项解析为各自的基本类型。

import groovy.json.JsonSlurper 
class Example {
   static void main(String[] args) {
      def jsonSlurper = new JsonSlurper()
      def obj = jsonSlurper.parseText ''' {"Integer": 12, "fraction": 12.55, "double": 12e13}'''
      println(obj.Integer);
      println(obj.fraction);
      println(obj.double); 
   } 
}

上述计划的输出如下 -

12 
12.55 
1.2E+14 

JsonOutput

现在让我们谈谈如何在Json中打印输出。 这可以通过JsonOutput方法完成。 此方法负责将Groovy对象序列化为JSON字符串。

语法 (Syntax)

Static string JsonOutput.toJson(datatype obj)

Parameters - 参数可以是数据类型的对象 - 数字,布尔值,字符,字符串,日期,映射,闭包等。

Return type - 返回类型是json字符串。

例子 (Example)

以下是如何实现这一目标的简单示例。

import groovy.json.JsonOutput 
class Example {
   static void main(String[] args) {
      def output = JsonOutput.toJson([name: 'John', ID: 1])
      println(output);  
   }
}

上述计划的输出如下 -

{"name":"John","ID":1}

JsonOutput也可以用于普通的groovy对象。 在下面的示例中,您可以看到我们实际上是将Student类型的对象传递给JsonOutput方法。

import groovy.json.JsonOutput  
class Example {
   static void main(String[] args) {
      def output = JsonOutput.toJson([ new Student(name: 'John',ID:1),
         new Student(name: 'Mark',ID:2)])
      println(output);  
   } 
}
class Student {
   String name
   int ID; 
}

上述计划的输出如下 -

[{"name":"John","ID":1},{"name":"Mark","ID":2}]

Groovy - DSLS

Groovy允许人们在顶级语句的方法调用的参数周围省略括号。 这被称为“命令链”功能。 这个扩展的工作原理是允许一个链接这种无括号的方法调用,既不需要围绕参数的括号,也不需要链接调用之间的点。

如果执行调用为abcd ,则实际上相当于a(b).c(d)

DSL或域特定语言旨在简化以Groovy编写的代码,使其易于为普通用户理解。 以下示例显示了具有特定于域的语言的确切含义。

def lst = [1,2,3,4] 
print lst

上面的代码显示了使用println语句打印到控制台的数字列表。 在域特定语言中,命令将为 -

Given the numbers 1,2,3,4
Display all the numbers

因此,上面的示例显示了编程语言的转换,以满足特定于域的语言的需要。

让我们看一个如何在Groovy中实现DSL的简单示例 -

class EmailDsl {  
   String toText 
   String fromText 
   String body 
   /** 
   * This method accepts a closure which is essentially the DSL. Delegate the 
   * closure methods to 
   * the DSL class so the calls can be processed 
   */ 
   def static make(closure) { 
      EmailDsl emailDsl = new EmailDsl() 
      // any method called in closure will be delegated to the EmailDsl class 
      closure.delegate = emailDsl
      closure() 
   }
   /** 
   * Store the parameter as a variable and use it later to output a memo 
   */ 
   def to(String toText) { 
      this.toText = toText 
   }
   def from(String fromText) { 
      this.fromText = fromText 
   }
   def body(String bodyText) { 
      this.body = bodyText 
   } 
}
EmailDsl.make { 
   to "Nirav Assar" 
   from "Barack Obama" 
   body "How are things? We are doing well. Take care" 
}

当我们运行上述程序时,我们将得到以下结果 -

How are things? We are doing well. Take care

关于上面的代码实现,需要注意以下几点 -

  • 使用接受闭包的静态方法。 这主要是实现DSL的一种无忧无虑的方式。

  • 在电子邮件示例中,类EmailDsl具有make方法。 它创建一个实例并将闭包中的所有调用委托给实例。 这是“to”和“from”部分最终在EmailDsl类中执行方法的机制。

  • 调用to()方法后,我们将文本存储在实例中以便稍后进行格式化。

  • 我们现在可以使用易于理解的最终用户语言来调用EmailDSL方法。

Groovy - Database

Groovy的groovy-sql模块提供了比当前Java JDBC技术更高级的抽象。 Groovy sql API支持各种各样的数据库,其中一些如下所示。

  • HSQLDB
  • Oracle
  • SQL Server
  • MySQL
  • MongoDB

在我们的示例中,我们将使用MySQL DB作为示例。 为了将MySQL与Groovy一起使用,首先要做的是从mysql站点下载MySQL jdbc jar文件。 MySQL的问题将在下面显示。

mysql-connector-java-5.1.38-bin

然后确保将上面的jar文件添加到工作站的类路径中。

数据库连接 (Database Connection)

在连接MySQL数据库之前,请确保以下内容 -

  • 您已经创建了一个数据库TESTDB。
  • 您已在TESTDB中创建了一个表EMPLOYEE。
  • 此表包含FIRST_NAME,LAST_NAME,AGE,SEX和INCOME字段。
  • 用户ID“testuser”和密码“test123”设置为访问TESTDB。
  • 确保已下载mysql jar文件并将该文件添加到类路径中。
  • 您已经通过MySQL教程来了解MySQL基础知识

以下示例显示如何连接MySQL数据库“TESTDB”。

import java.sql.*; 
import groovy.sql.Sql 
class Example {
   static void main(String[] args) {
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 
         'testuser', 'test123', 'com.mysql.jdbc.Driver')
      // Executing the query SELECT VERSION which gets the version of the database
      // Also using the eachROW method to fetch the result from the database
      sql.eachRow('SELECT VERSION()'){ row ->
         println row[0]
      }
      sql.close()  
   } 
} 

在运行此脚本时,它产生以下结果 -

5.7.10-log 
The Sql.newInstance method is used to establish a connection to the database.

创建数据库表

连接到数据库后的下一步是在数据库中创建表。 以下示例说明如何使用Groovy在数据库中创建表。 Sql类的execute方法用于执行针对数据库的语句。

import java.sql.*; 
import groovy.sql.Sql 
class Example { 
   static void main(String[] args) {
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser',  
         'test123', 'com.mysql.jdbc.Driver')
      def sqlstr = """CREATE TABLE EMPLOYEE ( 
         FIRST_NAME CHAR(20) NOT NULL,
         LAST_NAME CHAR(20),
         AGE INT,
         SEX CHAR(1),
         INCOME FLOAT )""" 
      sql.execute(sqlstr);
      sql.close() 
   } 
}

插入操作 (Insert Operation)

当您想要将记录创建到数据库表中时,它是必需的。

例子 (Example)

以下示例将在employee表中插入记录。 代码放在try catch块中,这样如果记录成功执行,则事务将提交给数据库。 如果事务失败,则完成回滚。

import java.sql.*; 
import groovy.sql.Sql 
class Example {
   static void main(String[] args) { 
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser', 
         'test123', 'com.mysql.jdbc.Driver')
      sql.connection.autoCommit = false
      def sqlstr = """INSERT INTO EMPLOYEE(FIRST_NAME,
         LAST_NAME, AGE, SEX, INCOME) VALUES ('Mac', 'Mohan', 20, 'M', 2000)""" 
      try {
         sql.execute(sqlstr);
         sql.commit()
         println("Successfully committed") 
      }catch(Exception ex) {
         sql.rollback()
         println("Transaction rollback") 
      }
      sql.close()
   } 
}

假设您只想根据条件选择某些行。 以下代码显示了如何添加参数占位符以搜索值。 也可以编写上面的示例来获取参数,如下面的代码所示。 $符号用于定义一个参数,然后在执行sql语句时可以用值替换该参数。

import java.sql.*; 
import groovy.sql.Sql
class Example {
   static void main(String[] args) {
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser', 
         'test123', 'com.mysql.jdbc.Driver')
      sql.connection.autoCommit = false  
      def firstname = "Mac"
      def lastname ="Mohan"
      def age = 20
      def sex = "M"
      def income = 2000  
      def sqlstr = "INSERT INTO EMPLOYEE(FIRST_NAME,LAST_NAME, AGE, SEX, 
         INCOME) VALUES " + "(${firstname}, ${lastname}, ${age}, ${sex}, ${income} )"
      try {
         sql.execute(sqlstr);
         sql.commit()
         println("Successfully committed") 
      } catch(Exception ex) {
         sql.rollback()
         println("Transaction rollback")
      }
      sql.close()
   }
}

读操作 (READ Operation)

READ对任何数据库的操作意味着从数据库中获取一些有用的信息。 建立数据库连接后,您就可以对此数据库进行查询。

通过使用sql类的eachRow方法执行读取操作。

语法 (Syntax)

eachRow(GString gstring, Closure closure) 

执行给定的SQL查询,使用结果集的每一行调用给定的Closure。

Parameters

  • Gstring - 需要执行的sql语句。

  • Closure - 用于处理从读取操作中恢复的行的closure语句。 执行给定的SQL查询,使用结果集的每一行调用给定的Closure。

以下代码示例显示如何从employee表中获取所有记录。

import java.sql.*; 
import groovy.sql.Sql
class Example {
   static void main(String[] args) {
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser', 
         'test123', 'com.mysql.jdbc.Driver')  
      sql.eachRow('select * from employee') {
         tp -> 
         println([tp.FIRST_NAME,tp.LAST_NAME,tp.age,tp.sex,tp.INCOME])
      }  
      sql.close()
   } 
}

上述计划的输出将是 -

[Mac, Mohan, 20, M, 2000.0]

更新操作 (Update Operation)

UPDATE对任何数据库的操作意味着更新一个或多个已在数据库中可用的记录。 以下过程将SEX的所有记录更新为“M”。 在这里,我们将所有男性的年龄增加一年。

import java.sql.*; 
import groovy.sql.Sql 
class Example {
   static void main(String[] args){
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser', 
         'test@123', 'com.mysql.jdbc.Driver')
      sql.connection.autoCommit = false
      def sqlstr = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = 'M'" 
      try {
         sql.execute(sqlstr);
         sql.commit()
         println("Successfully committed")
      }catch(Exception ex) {
         sql.rollback() 
         println("Transaction rollback")
      }
      sql.close()
   } 
}

删除操作

如果要从数据库中删除某些记录,则需要DELETE操作。 以下是从AGE超过20的EMPLOYEE中删除所有记录的程序。

import java.sql.*; 
import groovy.sql.Sql 
class Example {
   static void main(String[] args) {
      // Creating a connection to the database
      def sql = Sql.newInstance('jdbc:mysql://localhost:3306/TESTDB', 'testuser', 
         'test@123', 'com.mysql.jdbc.Driver')
      sql.connection.autoCommit = false
      def sqlstr = "DELETE FROM EMPLOYEE WHERE AGE > 20"
      try {
         sql.execute(sqlstr);
         sql.commit()
         println("Successfully committed")
      }catch(Exception ex) {
         sql.rollback()
         println("Transaction rollback")
      }
      sql.close()
   } 
}

执行事务 (Performing Transactions)

事务是一种确保数据一致性的机制。 交易具有以下四个属性 -

  • Atomicity - 事务完成或根本没有任何事情发生。

  • Consistency - 事务必须以一致状态启动,并使系统保持一致状态。

  • Isolation - 在当前事务之外不可见事务的中间结果。

  • Durability - 提交事务后,即使系统出现故障,影响也会持续存在。

这是一个如何实现事务的简单示例。 我们已经在上一个DELETE操作主题中看到了这个例子。

def sqlstr = "DELETE FROM EMPLOYEE WHERE AGE > 20" 
try {
   sql.execute(sqlstr); 
   sql.commit()
   println("Successfully committed") 
}catch(Exception ex) {
   sql.rollback()
   println("Transaction rollback") 
} 
sql.close()

提交操作 (Commit Operation)

提交操作告诉数据库继续执行操作并最终完成对数据库的所有更改。

在上面的例子中,这是通过以下声明实现的 -

sql.commit()

回滚操作 (Rollback Operation)

如果您对一个或多个更改不满意并且想要完全还原这些更改,请使用回滚方法。 在上面的例子中,这是通过以下声明实现的 -

sql.rollback()

断开数据库连接

要断开数据库连接,请使用close方法。

sql.close()

Groovy - Builders

在软件开发过程中,有时开发人员会花费大量时间来创建数据结构,域类,XML,GUI布局,输出流等。有时,用于创建这些特定需求的代码会导致重新生成相同的片段。很多地方的代码。 这就是Groovy构建者发挥作用的地方。 Groovy具有可用于创建标准对象和结构的构建器。 这些构建器节省了时间,因为开发人员不需要编写自己的代码来创建这些构建器。 在本章的内容中,我们将介绍groovy中可用的不同构建器。

Swing Builder

在groovy中,还可以使用groovy中提供的swing构建器创建图形用户界面。 开发swing组件的主要类是SwingBuilder类。 这个类有很多方法可用于创建图形组件,例如 -

  • JFrame - 用于创建框架元素。

  • JTextField - 用于创建文本域组件。

让我们看一个如何使用SwingBuilder类创建Swing应用程序的简单示例。 在以下示例中,您可以看到以下几点 -

  • 您需要导入groovy.swing.SwingBuilder和javax.swing。*类。

  • Swing应用程序中显示的所有组件都是SwingBuilder类的一部分。

  • 对于框架本身,您可以指定框架的初始位置和大小。 您还可以指定框架的标题。

  • 您需要将Visibility属性设置为true才能显示框架。

import groovy.swing.SwingBuilder 
import javax.swing.* 
// Create a builder 
def myapp = new SwingBuilder()
// Compose the builder 
def myframe = myapp.frame(title : 'IOWIKI', location : [200, 200], 
   size : [400, 300], defaultCloseOperation : WindowConstants.EXIT_ON_CLOSE {         
      label(text : 'Hello world')
   } 
// The following  statement is used for displaying the form 
frame.setVisible(true)

上述程序的输出如下。 以下输出显示JFrame以及带有Hello World文本的JLabel。

JLabel带文字

让我们看看下一个用文本框创建输入屏幕的示例。 在下面的示例中,我们要创建一个表单,其中包含学生姓名,主题和学校名称的文本框。 在以下示例中,您可以看到以下要点 -

  • 我们正在为屏幕上的控件定义布局。 在这种情况下,我们使用网格布局。
  • 我们正在为标签使用对齐属性。
  • 我们使用textField方法在屏幕上显示文本框。
import groovy.swing.SwingBuilder 
import javax.swing.* 
import java.awt.*
// Create a builder 
def myapp = new SwingBuilder() 
// Compose the builder 
def myframe = myapp.frame(title : 'IOWIKI', location : [200, 200], 
   size : [400, 300], defaultCloseOperation : WindowConstants.EXIT_ON_CLOSE) { 
      panel(layout: new GridLayout(3, 2, 5, 5)) { 
         label(text : 'Student Name:', horizontalAlignment : JLabel.RIGHT) 
         textField(text : '', columns : 10) 
         label(text : 'Subject Name:', horizontalAlignment : JLabel.RIGHT) 
         textField(text : '', columns : 10)
         label(text : 'School Name:', horizontalAlignment : JLabel.RIGHT) 
         textField(text : '', columns : 10) 
      } 
   } 
// The following  statement is used for displaying the form 
myframe.setVisible(true)

上述计划的输出如下 -

显示表格

事件处理程序

现在让我们看一下事件处理程序。 当按下按钮时,事件处理程序用于按钮执行某种处理。 每个按钮伪方法调用包括actionPerformed参数。 这表示作为闭包呈现的代码块。

让我们看看下一个用2个按钮创建屏幕的例子。 按下任一按钮时,相应的消息将发送到控制台屏幕。 在以下示例中,您可以看到以下要点 -

  • 对于定义的每个按钮,我们使用actionPerformed方法并定义一个闭包,以便在单击按钮时将一些输出发送到控制台。

import groovy.swing.SwingBuilder 
import javax.swing.* 
import java.awt.* 
def myapp = new SwingBuilder()
def buttonPanel = {
   myapp.panel(constraints : BorderLayout.SOUTH) {
      button(text : 'Option A', actionPerformed : {
         println 'Option A chosen'
      })
      button(text : 'Option B', actionPerformed : {
         println 'Option B chosen'
      })
   }
}
def mainPanel = {
   myapp.panel(layout : new BorderLayout()) {
      label(text : 'Which Option do you want', horizontalAlignment : 
      JLabel.CENTER,
      constraints : BorderLayout.CENTER)
      buttonPanel()
   }
}
def myframe = myapp.frame(title : 'IOWIKI', location : [100, 100],
   size : [400, 300], defaultCloseOperation : WindowConstants.EXIT_ON_CLOSE){
      mainPanel()
   }
myframe.setVisible(true)

上述程序的输出如下。 单击任一按钮时,所需的消息将发送到控制台日志屏幕。

选项按钮

上述示例的另一个变体是定义可以充当处理程序的方法。 在下面的示例中,我们定义了DisplayA和DisplayB的2个处理程序。

import groovy.swing.SwingBuilder 
import javax.swing.* 
import java.awt.* 
def myapp = new SwingBuilder()
def DisplayA = {
   println("Option A") 
} 
def DisplayB = {
   println("Option B")
}
def buttonPanel = {
   myapp.panel(constraints : BorderLayout.SOUTH) {
      button(text : 'Option A', actionPerformed : DisplayA) 
      button(text : 'Option B', actionPerformed : DisplayB)
   }
}  
def mainPanel = {
   myapp.panel(layout : new BorderLayout()) {
      label(text : 'Which Option do you want', horizontalAlignment : JLabel.CENTER,
      constraints : BorderLayout.CENTER)
      buttonPanel()
   }
}  
def myframe = myapp.frame(title : 'IOWIKI', location : [100, 100],
   size : [400, 300], defaultCloseOperation : WindowConstants.EXIT_ON_CLOSE) {
      mainPanel()
   } 
myframe.setVisible(true) 

上述程序的输出将与前面的示例保持一致。

DOM Builder

DOM构建器可用于解析HTML,XHTML和XML并将其转换为W3C DOM树。

以下示例显示了如何使用DOM构建器。

String records = '''
   <library>
      <Student>
         <StudentName division = 'A'>Joe</StudentName>
         <StudentID>1</StudentID>
      </Student>
      <Student>
         <StudentName division = 'B'>John</StudentName>
         <StudentID>2</StudentID>
      </Student>
      <Student>
         <StudentName division = 'C'>Mark</StudentName>
         <StudentID>3</StudentID>
      </Student>
   </library>'''
def rd = new StringReader(records) 
def doc = groovy.xml.DOMBuilder.parse(rd)

JsonBuilder

JsonBuilder用于创建json类型对象。

以下示例显示了如何使用Json构建器。

def builder = new groovy.json.JsonBuilder() 
def root = builder.students {
   student {
      studentname 'Joe'
      studentid '1'
      Marks(
         Subject1: 10,
         Subject2: 20,
         Subject3:30,
      )
   } 
} 
println(builder.toString());

上述程序的输出如下。 输出clearlt显示Jsonbuilder能够从一组结构节点构建json对象。

{"students":{"student":{"studentname":"Joe","studentid":"1","Marks":{"Subject1":10,
"S ubject2":20,"Subject3":30}}}}

jsonbuilder还可以接受列表并将其转换为json对象。 以下示例说明了如何实现此目的。

def builder = new groovy.json.JsonBuilder() 
def lst = builder([1, 2, 3]) 
println(builder.toString());

上述程序的输出如下。

[1,2,3]

jsonBuilder也可以用于类。 以下示例显示了类的对象如何成为json构建器的输入。

def builder = new groovy.json.JsonBuilder() 
class Student {
   String name  
} 
def studentlist = [new Student (name: "Joe"), new Student (name: "Mark"), 
   new Student (name: "John")] 
builder studentlist, { Student student ->name student.name} 
println(builder)

上述程序的输出如下。

[{"name":"Joe"},{"name":"Mark"},{"name":"John"}] 

NodeBuilder (NodeBuilder)

NodeBuilder用于创建Node对象的嵌套树,以处理任意数据。 Nodebuilder的使用示例如下所示。

def nodeBuilder = new NodeBuilder() 
def studentlist = nodeBuilder.userlist {
   user(id: '1', studentname: 'John', Subject: 'Chemistry')
   user(id: '2', studentname: 'Joe', Subject: 'Maths')
   user(id: '3', studentname: 'Mark', Subject: 'Physics') 
} 
println(studentlist)

FileTreeBuilder

FileTreeBuilder是一个用于从规范生成文件目录结构的构建器。 以下是如何使用FileTreeBuilder的示例。

tmpDir = File.createTempDir() 
def fileTreeBuilder = new FileTreeBuilder(tmpDir) 
fileTreeBuilder.dir('main') {
   dir('submain') {
      dir('Tutorial') {
        file('Sample.txt', 'println "Hello World"')
      }
   } 
}

从执行上面的代码开始,将在main/submain/Tutorial文件夹中创建一个名为sample.txt的文件。 sample.txt文件将包含“Hello World”文本。

Groovy - Command Line

称为groovysh的Groovy shell可以很容易地用于评估groovy表达式,定义类和运行简单程序。 安装Groovy时会安装命令行shell。

以下是Groovy中可用的命令行选项 -

命令行参数 全名 细节
-C--color[=FLAG] 启用或禁用ANSI颜色的使用
-D--define=NAME=VALUE 定义系统属性
-T--terminal=TYPE 指定要使用的终端TYPE
-V--version 显示版本
-classpath 指定查找类文件的位置 - 必须是第一个参数
-cp--classpathAliases for '-classpath'
-d--debug--debug Enable debug output
-e--evaluate=arg 在开始交互式会话时评估选项拳头
-h--help 显示此帮助消息
-q--quietSuppress superfluous output
-v--verboseEnable verbose output

以下快照显示了在Groovy shell中执行的表达式的简单示例。 在下面的例子中,我们只是在groovy shell中打印“Hello World”。

Groovy Shell

类和函数 (Classes and Functions)

在命令提示符中定义类,创建新对象并在类上调用方法非常容易。 以下示例显示了如何实现此功能。 在下面的示例中,我们使用一个简单的方法创建一个简单的Student类。 在命令提示符本身中,我们正在创建类的对象并调用Display方法。

创建标准类

在命令提示符中定义方法并调用该方法非常容易。 请注意,该方法是使用def类型定义的。 另请注意,我们已经包含一个名为name的参数,然后在调用Display方法时将其替换为实际值。 以下示例显示了如何实现此功能。

提示并调用命令

Commands

shell有许多不同的命令,可以提供对shell环境的丰富访问。 以下是它们的列表以及它们的作用。

Sr.No Command&smp; 命令说明
1

:help

(:h)显示此帮助消息

2

?

(:?)Alias to :: help

3

:exit

(:x)退出shell

4

:quit

(:q)别名为:退出

5

import

(:i)将类导入命名空间

6

:display

(:d)显示当前缓冲区

7

:clear

(:c)清除缓冲区并重置提示计数器

8

:show

(:S)显示变量,类或导入

9

:inspect

(:n)使用GUI对象浏览器检查变量或最后一个结果

10

:purge

(:p)清除变量,类,导入或首选项

11

:edit

(:e)编辑当前缓冲区

12

:load

(:l)将文件或URL加载到缓冲区中

13

.

(:。)Alias to :: load

14

.save

(:s)将当前缓冲区保存到文件中

15

.record

(:r)将当前会话记录到文件中

16

:alias

(:a)创建别名

17

:set

(:=)设置(或列表)首选项

18

:register

(:rc)向shell注册一个新命令

19

:doc

(:D)打开一个显示参数文档的浏览器窗口

20

:history

(:H)显示,管理和调用编辑行历史记录

Groovy - Unit Testing

面向对象系统的基本单元是类。 因此,单元测试由一个类中的testig组成。 采用的方法是创建测试类的对象,并使用它来检查所选方法是否按预期执行。 并非每种方法都可以进行测试,因为测试每一种方法并不总是有用的。 但是应该对关键和关键方法进行单元测试。

JUnit是一个开源测试框架,是Java代码自动化单元测试的公认行业标准。 幸运的是,JUnit框架可以很容易地用于测试Groovy类。 所需的只是扩展GroovyTestCase类,它是标准Groovy环境的一部分。 Groovy测试用例类基于Junit测试用例。

编写简单的Junit测试用例

假设我们在应用程序类文件中定义了以下类 -

class Example {
   static void main(String[] args) {
      Student mst = new Student();
      mst.name = "Joe";
      mst.ID = 1;
      println(mst.Display())
   } 
} 
public class Student {
   String name;
   int ID;
   String Display() {
      return name +ID;
   }  
}

上述程序的输出如下。

Joe1

现在假设我们想为Student类编写一个测试用例。 典型的测试用例如下所示。 关于以下代码需要注意以下几点 -

  • 测试用例类扩展了GroovyTestCase类
  • 我们使用assert语句来确保Display方法返回正确的字符串。
class StudentTest extends GroovyTestCase {
   void testDisplay() {
      def stud = new Student(name : 'Joe', ID : '1')
      def expected = 'Joe1'
      assertToString(stud.Display(), expected)
   }
}

Groovy测试套件

通常随着单元测试的数量增加,将难以一个接一个地继续执行所有测试用例。 因此,Groovy提供了创建测试套件的工具,可以将所有测试用例封装到一个逻辑单元中。 以下codesnippet显示了如何实现这一目标。 关于代码,应注意以下事项 -

  • GroovyTestSuite用于将所有测试用例封装为一个。

  • 在下面的示例中,我们假设我们有两个测试用例文件,一个名为StudentTest ,另一个是EmployeeTest ,其中包含所有必要的测试。

import groovy.util.GroovyTestSuite 
import junit.framework.Test 
import junit.textui.TestRunner 
class AllTests { 
   static Test suite() { 
      def allTests = new GroovyTestSuite() 
      allTests.addTestSuite(StudentTest.class) 
      allTests.addTestSuite(EmployeeTest.class) 
      return allTests 
   } 
} 
TestRunner.run(AllTests.suite())

Groovy - Template Engines

Groovy的模板引擎就像邮件合并一样(从数据库中自动添加名称和地址到字母和信封,以便于向许多地址发送邮件,特别是广告),但它更为通用。

简单的字符串模板

如果你采用下面的简单示例,我们首先定义一个名称变量来保存字符串“Groovy”。 在println语句中,我们使用$ symbol来定义可以插入值的参数或模板。

def name = "Groovy" 
println "This Tutorial is about ${name}"

如果上面的代码在groovy中执行,将显示以下输出。 输出清楚地显示$ name被def语句指定的值替换。

简单的模板引擎

以下是SimpleTemplateEngine的示例,它允许您在模板中使用类似JSP的scriptlet和EL表达式,以生成参数化文本。 模板引擎允许您绑定参数列表及其值,以便可以在具有已定义占位符的字符串中替换它们。

def text ='This Tutorial focuses on $TutorialName. In this tutorial you will learn 
about $Topic'  
def binding = ["TutorialName":"Groovy", "Topic":"Templates"]  
def engine = new groovy.text.SimpleTemplateEngine() 
def template = engine.createTemplate(text).make(binding) 
println template

如果上面的代码在groovy中执行,将显示以下输出。

现在让我们使用模板的XML文件。 作为第一步,我们将以下代码添加到名为Student.template的文件中。 在以下文件中,您将注意到我们尚未添加元素的实际值,而是添加了占位符。 所以$ name,$ is和$ subject都被放置为占位符,需要在运行时替换。

<Student> 
   <name>${name}</name> 
   <ID>${id}</ID> 
   <subject>${subject}</subject> 
</Student>

现在让我们添加我们的Groovy脚本代码来添加可用于将实际值替换为上述模板的功能。 关于以下代码,应注意以下事项。

  • 占位符到实际值的映射是通过绑定和SimpleTemplateEngine完成的。 绑定是一个Map,其中占位符为键,替换为值。

import groovy.text.* 
import java.io.* 
def file = new File("D:/Student.template") 
def binding = ['name' : 'Joe', 'id' : 1, 'subject' : 'Physics']
def engine = new SimpleTemplateEngine() 
def template = engine.createTemplate(file) 
def writable = template.make(binding) 
println writable

如果上面的代码在groovy中执行,将显示以下输出。 从输出可以看出,值已在相关占位符中成功替换。

<Student> 
   <name>Joe</name> 
   <ID>1</ID> 
   <subject>Physics</subject> 
</Student>

StreamingTemplateEngine

StreamingTemplateEngine引擎是Groovy中另一个模板引擎。 这类似于SimpleTemplateEngine,但使用可写闭包创建模板,使其对大型模板更具可伸缩性。 特别是这个模板引擎可以处理大于64k的字符串。

以下是如何使用StreamingTemplateEngine的示例 -

def text = '''This Tutorial is <% out.print TutorialName %> The Topic name 
is ${TopicName}''' 
def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)
def binding = [TutorialName : "Groovy", TopicName  : "Templates",]
String response = template.make(binding) 
println(response)

如果上面的代码在groovy中执行,将显示以下输出。

This Tutorial is Groovy The Topic name is Templates

XMLTemplateEngine

XmlTemplateEngine用于模板场景,其中模板源和预期输出都是XML。 模板使用普通的$ {expression}和$ variable表示法将任意表达式插入模板中。

以下是如何使用XMLTemplateEngine的示例。

def binding = [StudentName: 'Joe', id: 1, subject: 'Physics'] 
def engine = new groovy.text.XmlTemplateEngine() 
def text = '''\
   <document xmlns:gsp='http://groovy.codehaus.org/2005/gsp'>
      <Student>
         <name>${StudentName}</name>
         <ID>${id}</ID>
         <subject>${subject}</subject>
      </Student>
   </document> 
''' 
def template = engine.createTemplate(text).make(binding) 
println template.toString()

如果上面的代码在groovy中执行,将显示以下输出

   Joe
   1
   Physics 

Groovy - Meta Object Programming

元对象编程或MOP可用于动态调用方法,还可以动态创建类和方法。

那么这是什么意思? 让我们考虑一个名为Student的类,它是一个没有成员变量或方法的空类。 假设您必须在此类上调用以下语句。

Def myStudent = new Student() 
myStudent.Name = ”Joe”; 
myStudent.Display()

现在在元对象编程中,即使类没有成员变量Name或方法Display(),上面的代码仍然可以工作。

这怎么办? 好吧,为了解决这个问题,必须实现GroovyInterceptable接口来挂钩Groovy的执行过程。 以下是此接口可用的方法。

Public interface GroovyInterceptable { 
   Public object invokeMethod(String methodName, Object args) 
   Public object getproperty(String propertyName) 
   Public object setProperty(String propertyName, Object newValue) 
   Public MetaClass getMetaClass() 
   Public void setMetaClass(MetaClass metaClass) 
}

因此,在上面的接口描述中,假设您必须实现invokeMethod(),将为每个存在或不存在的方法调用它。

缺少属性

那么让我们看一下如何为缺少的属性实现元对象编程的示例。 关于以下代码,应注意以下注意事项。

  • Student类没有定义名为Name或ID的成员变量。

  • Student类实现了GroovyInterceptable接口。

  • 有一个名为dynamicProps的参数,用于保存动态创建的成员变量的值。

  • 已经实现了getproperty和setproperty方法,以便在运行时获取和设置类的属性值。

class Example {
   static void main(String[] args) {
      Student mst = new Student();
      mst.Name = "Joe";
      mst.ID = 1;
      println(mst.Name);
      println(mst.ID);
   }
}
class Student implements GroovyInterceptable { 
   protected dynamicProps=[:]
   void setProperty(String pName,val) {
      dynamicProps[pName] = val
   }
   def getProperty(String pName) {
      dynamicProps[pName]
   } 
} 

以下代码的输出将是 -

Joe 
1

缺少方法

那么让我们看一下如何为缺少的属性实现元对象编程的示例。 关于以下代码应注意以下注意事项 -

  • Student类现在实现了invokeMethod方法,无论方法是否存在,都会调用该方法。

class Example {
   static void main(String[] args) {
      Student mst = new Student();
      mst.Name = "Joe";
      mst.ID = 1;
      println(mst.Name);
      println(mst.ID);
      mst.AddMarks();
   } 
}
class Student implements GroovyInterceptable {
   protected dynamicProps = [:]  
   void setProperty(String pName, val) {
      dynamicProps[pName] = val
   } 
   def getProperty(String pName) {
      dynamicProps[pName]
   }
   def invokeMethod(String name, Object args) {
      return "called invokeMethod $name $args"
   }
}

以下代码的输出如下所示。 请注意,即使方法显示不存在,也没有错过方法异常的错误。

Joe 
1 

元类(Metaclass)

此功能与MetaClass实现有关。 在默认实现中,您可以访问字段而无需调用其getter和setter。 以下示例显示了如何通过使用metaClass函数,我们能够更改类中私有变量的值。

class Example {
   static void main(String[] args) {
      Student mst = new Student();
      println mst.getName()
      mst.metaClass.setAttribute(mst, 'name', 'Mark')
      println mst.getName()
   } 
} 
class Student {
   private String name = "Joe";
   public String getName() {
      return this.name;
   } 
}

以下代码的输出将是 -

Joe 
Mark

方法缺失

Groovy支持methodMissing的概念。 此方法与invokeMethod的不同之处在于,只有在方法分派失败的情况下才会调用此方法,此时无法找到给定名称和/或给定参数的方法。 以下示例显示了如何使用methodMissing。

class Example {
   static void main(String[] args) {
      Student mst = new Student();
      mst.Name = "Joe";
      mst.ID = 1;
      println(mst.Name);
      println(mst.ID);
      mst.AddMarks();
   } 
} 
class Student implements GroovyInterceptable {
   protected dynamicProps = [:]  
   void setProperty(String pName, val) {
      dynamicProps[pName] = val
   }
   def getProperty(String pName) {
      dynamicProps[pName]
   }
   def methodMissing(String name, def args) {         
      println "Missing method"
   }  
}

以下代码的输出将是 -

Joe 
1 
Missing method 
↑回到顶部↑
WIKI教程 @2018