Groovy Basic syntax

A, variables,

1, type,

Object types, primitive types (essentially object types)

int x = 0
println x.class
double y = 3.14
println y.class
Copy the code

Output:

class java.lang.Integer
class java.lang.Double
Copy the code

Conclusion: As you can see from the log output, there are essentially no primitive types in Groovy, but boxing object types in Java.

2, definitions,

Strong type definition method, weak type def definition method

def x_1 = 11
println x_1.class
def y_1 = 3.1415
println y_1.class
def name = 'Android'
println name.class
Copy the code

Output:

class java.lang.Integer
class java.math.BigDecimal
class java.lang.String
Copy the code

2. String

String, GString

1. Three commonly used definition methods

// Single quotes: the same as strings in Java
def name = 'a single \'a\' string'
println name.class
// Triple quotation marks: format can be specified directly (e.g. newline, no need for \n, no need for + sign concatenation in code representation)
def thupleName = '''three single string'''
println thupleName.class
// Double quotation marks: To specify different lines of text (i.e. not immediately following the text after the triple quotation marks), use \.
def thupleName1 = '''\
line one
line two
line three'''
println thupleName1
// Double quotes: extendable string (i.e., variable, expression, etc.)
def doubleName = "this a common String" // String
println doubleName.class
def doubleName1 = "Hello: ${name}" // GString
println doubleName1.class
Copy the code
// Single quotes class java.lang.String // triple quotes class java.lang.String line one line two line three // double quotes class java.lang.String class org.codehaus.groovy.runtime.GStringImplCopy the code

2. Add operators

Method sources: Java.lang. String, DefaultGroovyMethods, StringGroovyMethods (parameters of normal type, parameters of closure type)

def str = "groovy"
def str2 = "gro"
// Center (numberOfChars, padding) : Padding is used to populate both sides of the existing string
// Center (numberOfChars) : padding both sides of an existing string with Spaces
println str.center(8.'a')
// padLeft(numberOfChars, padding) : Padding the left side of the existing string using the padding
println str.padLeft(8.'a')
// Compare: you can use the > and < symbols for direct comparisons instead of using compareTo()
println str > str2
String [index] (equivalent to string.getat (index))
println str[0]
println str[0.1.]
// Subtract strings: You can use the - sign directly to get the same effect as minus()
println str - str2 // str.minus(str2)
/ / reverse
println str.reverse()
// Uppercase
println str.capitalize()
// Check if it is a number
println str.isNumber()
Copy the code

Output:

// center agroovya // padLef aagroovy // str > str2 true // str[0] g // str[0..1] gr // str - str2 ovy // reverse yvoorg  // capitalize Groovy // isNumber falseCopy the code

3. Added API explanation

Logic control: sequential logic (single step down), conditional logic (if/else, switch/case), circular logic (while, for)

// ============= conditional logic =============
def x = 1.23
def result
switch(x){
  case 'foo':
    result = 'found foo'
    break
  case [4.5.6.'inlist'] :/ / list
    result = 'list'
    break
  case 12.30.: / / range
    result = "range"
    break
  case Integer:
    result = 'integer'
    break
  case BigDecimal:
    result = 'big decimal'
    break
  default:
    result = 'default'
    break
}
println result

// ============= loop logic =============
def sum = 0
// For loop for scope
for(i in 0.9.){sum += i}
// Loop through List
for(i in [0.1.2.3.4.5.6.7.8.9]){sum += i}
// Loop through Map
for(i in ["lili":1."luck":2."xiaoming":3]){
  sum += i.value
}
Copy the code

Output:

// x = 1.23
big decimal
// x = 4
list
Copy the code

Groovy closure tutorial

A basis,

Closure concepts (definitions, calls), closure arguments (normal, implicit arguments), closure return values (always return values)

// ============= Closure concept =============
/ / define
def clouser = {println 'Hello groovy! '}
// Call 1:
clouser.call()
// Call 2:
clouser()

// ============= closure arguments =============
// Common parameters
def clouser = {String name, int age -> println "Hello ${name}, my age is ${age}"}
clouser('groovy! '.18) // clouser.call('groovy! ', 18)
// Implicit arguments (it is the default argument that all closures have; it fails when explicitly declared arguments are used)
def clouser = {println "Hello ${it}"}
clouser('groovy! ')

// ============= closure returns the value =============
def clouser = {return 'Hello, groovy! '} // Return Hello, groovy
def result = clouser()
println result

def clouser = {println 'Hello groovy! '} / / returns null
def result = clouser()
println result
Copy the code

Second, the use of

Closure usage: with primitive types, with strings, with data structures, with files, and so on

// ============= is used with the base type =============
int x = fab(5)
println x
// Find the factorial of the specified number
int fab(int number){
  int result = 1
  1.upto(number, {num -> result *= num}) // upto() is wrapped in DefaultGroovyMethods
  return result
}
int fab2(int number){
  int result = 1
  number.downto(1) {// Closures can be written outside parentheses instead of inside them
    num -> result *= num
  }
  return result
}
// loop from 0 to number
int cal(int number){
  int result = 1
  number.times { // Times (Closure) accepts only one Closure and writes it outside parentheses. Parentheses can be omitted
    num -> result += num
  }
  return result
}

// ============= uses the package parameter ============= with String
String str = 'the 2 and 3 is 5'
// each: iterates over each character
str.each {
  String temp -> print temp
}
// find: find the first one that matches the condition
println str.find {
  String s -> s.isNumber()
}
// findAll: finds all characters that match the conditions
def list = str.findAll {
  String s -> s.isNumber()
}
println list.toListString()
// any: iterates over each character, returning true as long as conditions are met
def result= str.any {
  String s -> s.isNumber()
}
println result
// every: iterates over every character, all of which must meet the condition to return true
println str.every {
  String s -> s.isNumber
}
// collect: iterate over each character, after closure processing, add to list and return
def list = str.collect { it.toUpperCase() }
println list.toListString()

// ============= is used in conjunction with data structures =============
// ============= is used in combination with files such as =============
// This will be covered in a later chapter

Copy the code

Output:

/ / = = = = = = = = = = = = = with String using packet parameter = = = = = = = = = = = = = / / each of the 2 and 3 is 5 2 / / / / find the final All [2, 3, 5] // any true // every false // collect [T, H, E, , 2, , A, N, D, , 3, , I, S, , 5]Copy the code

Third, the advanced

Closure key variables (this, owner, delegate)

// this == owner == delegate
def scriptClosure = {
  println "scriptClosure this:"+this // represents the class at the closure definition
  println "scriptClosure owner:"+owner // represents the class or object at the closure definition
  println "scriptClosure delegate:"+delegate // Code arbitrary object, default is the same as owner
}
scriptClosure.call()

// this ! = owner == delegate
def nestClosure = {
  def innerClosure = {
    prinln "innerClosure this:"+this
    prinln "innerClosure owner:"+owner
    prinln "innerClosure delegate:"+delegate
  }
  innerClosure.call()
}

// this ! = owner ! = delegate
def nestClosure = {
  def innerClosure = {
    prinln "innerClosure this:"+this
    prinln "innerClosure owner:"+owner
    prinln "innerClosure delegate:"+delegate
  }
  innerClosure.delegate = new Person() // Manually modify the delegate value
  innerClosure.call()
}
Copy the code

The output

// this == owner == delegate scriptClosure this:variable.closurestudy@2ef3eef9 scriptClosure owner:variable.closurestudy@2ef3eef9 scriptClosure delegate:variable.closurestudy@2ef3eef9 // this ! = owner == delegate innerClosure this:variable.closurestudy@2ef3eef9 innerClosure owner:variable.closurestudy$_run_closure2@402bba4f innerClosure delegate:variable.closurestudy$_run_closure2@402bba4f //  this ! = owner ! = delegate innerClosure this:variable.closurestudy@2ef3eef9 innerClosure owner:variable.closurestudy$_run_closure2@402bba4f innerClosure delegate:variable.Person@795cd85eCopy the code

Conclusion:

  • In most data cases, the values of this, owner, and delegate are the same.
  • When defining a closure within a closure, the value of this and owner are different. (This refers to the class object at the closure definition, owner refers to the closure object in the class at the closure definition)
  • The owner and delegate values are different only when the closure delegate is manually modified.

Closure delegate policies (Closure.OWNER_FIRST, Closure.OWNER_ONLY, Closure.DELEGATE_FIRST, Closure.DELEGATE_ONLY)

class Studen{
  String name
  def pretty = { "My name is ${name}" }
  String toString(){
    pretty.call()
  }
}

Class Teacher{
  String name1 // Note: this is not the same as the name of the Student variable!!
}

def stu = new Studen(name: "Lqr")
def tea = new Teacher(name1: "Lxf")

/ / 1, Normal
println stu.toString()

// select delegate
stu.pertty.delegate = tea
stu.pertty.resolveStrategy = Closure.DELEGATE_FIRST
println stu.toString()

// delegate only
stu.pertty.delegate = tea
stu.pertty.resolveStrategy = Closure.DELEGATE_ONLY
println stu.toString()
Copy the code

Output:

// 1, delegate My name is Lqr // 2, delegate My name is Lqr // No Such property: name for class Teacher. Delegate: name for class TeacherCopy the code

Groovy data structure

A list,

Definition, operation (add, delete, check and row)

// List definition
def list = [1.2.3.4.5] // Lists in Groovy are arrayLists
println list.class
println list.size()
// Array definition
def array = [1.2.3.4.5] as int[] // Use the as int[] conversion
int[] array = [1.2.3.4.5] // Use strong typing

// add ============= to the list =============
list.add(6)
list.leftShift(7)
list << 8
println list.toListString()
def plusList = list + 9
println plusList.toListString()

// delete the list ============= =============
list.remove(7)
list.remove((Object)7)
list.removeAt(7)
list.removeElement(6)
list.removeAll { return it % 2= =0}
println list - [6.7]
println list.toListString()
 
// ============= sort the list =============
def sortList = [6 - 3.9.2.7 -.1.5]
sortList.sort() // In Java: collections.sort (sortList)
println sortList
// Custom collation: Sort by the opposite direction of absolute valuesortList.sort { a,b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? 1:- 1
}
// Custom sort rules: Sort by string length
def sortStringList = ['abc'.'z'.'Hello'.'groovy'.'java']
sortStringList.sort { it -> return it.size()}
println sortStringList

// ============= list lookup =============
def findList = [- 3.9.6.2.7 -.1.5]
// find() : returns the first element that matches the criteria
int result = findList.find { return it % 2= =0}
println result
// findAll() : returns all elements that match the criteria
def resultfindList.findAll{ return it % 2! =0}
println result.toListString()
// any() : Returns true if one of the lists meets the criteria
def result = findList.any { return it % 2! =0} 
println result
// every() : Returns true for all elements in the list
def result = findList.every {return it % 2! =0}
println result
// min() : returns the minimum value
println findList.min() // findlist. min {return math.abs (it)} find the minimum absolute value
// Max () : returns the maximum value
println findList.max() // findList. Max {return math.abs (it)} find the maximum absolute value
// count() : counts the number of eligible elements
def num = findList.count { return it % 2= =0}
println num
Copy the code

The output

/ / list the definition of a class in Java. Util. ArrayList 5 / / = = = = = = = = = = = = = list ordering = = = = = = = = = = = = = [7, 3, 1, 2, 5, 6, 9] / / custom ordering rules: Sort by reverse absolute value [9, -7, 6, 5, -3, 2, 1] According to the length of the string sort [' z ', 'ABC' and 'Java', 'Hello,' groovy '] / / = = = = = = = = = = = = = list lookup = = = = = = = = = = = = = / / find 6 / / the.findall () [3, 9, 7, 1, 5] // every() false // min() 1 // Max () 9 // count() 2Copy the code

Second, the mapping

/ / define
def colors = [
  red : 'ff0000'.green : '00ff00'.blue : '0000ff'
]
println colors.getClass() // Note: You cannot use colors. Class directly, because this will look for elements whose key is class
// def colors = [...] As HashMap or HashMap colors = [...]

// Index
println colors['red']
println colors.red
println colors.blue
// Add elements
colors.yellow = 'ffff00'    // Add key-value of the same type
colors.complex = [a:1.b:2] // Add any key-value type
println colors.toMapString()
// Delete elements
colors.remove(red)

def students = [
  1: [number: '0001'.name: 'Bob'.score: 55.sex: 'male'].  2: [number: '0002'.name: 'Johnny'.score: 62.sex: 'female']
  3: [number: '0003'.name: 'Claire'.score: 73.sex: 'female']
  4: [number: '0004'.name: 'Amy' ,score: 66.sex: 'male']]/ / traverse
students.each { def student -> 
  println "the key is ${student.key}, "+
    "the value is ${student.value}"
}
// index traversal
students.eachWithIndex { def student, int index ->
  println "the index is ${index}, "+
    "the key is ${student.key}, "+
    "the value is ${student.value}"
}
// Directly iterate over key-valuestudents.each { key, value -> ... } students.eachWithIndex { key, value, index -> ... }/ / to find
def entry = students.find { def student ->
  return student.value.score >= 60
}
println entry
def entrys = students.findAll { def student ->
  return student.value.score >= 60
}
println entrys
// Count the number of boys who passed the exam
def count =  students.count { def student ->
  return student.value.score >= 60 && student.value.sex == 'male'
}
println count
// Filter: get the names of all passing students
def names = students.findAll { def student ->
  return student.value.score >= 60
}.collect{ // Filter out the element specified attribute column
  return it.value.name
}
println names.toListString()
// Divide students into groups
def group = students.groupBy {def student ->
  return student.value.score >= 60? 'Pass' :'Fail'
}
println group.toMapString()

/ / sorting
def sort = students.sore { def student1, def students ->
  Number score1 = student1.value.score
  Number score2 = student2.value.score
  returnscore1 == score2 ? 0 : score1 < score2 ? 1:1
}
println sort
Copy the code
// Define class java.util.LinkedHashMap // index ff0000 ff0000 0000ff // Add elements [red:ff0000, green: 00FF00, blue:0000ff, Yellow :ffff00, complex:[a:1, b:2]] thie value is [number:0001, name:Bob, score:55, sex:male] the key is 2, thie value is [number:0002, name:Johnny, score:62, sex:female] the key is 3, thie value is [number:0003, name:Claire, score:73, sex:female] the key is 4, thie value is [number:0004, name:Amy, Thie value is [number:0001, name:Bob, score:55, thie value is [number:0001, name:Bob, score:55, sex:male] the index is 1, the key is 2, thie value is [number:0002, name:Jhonny, score:62, sex:female] the index is 2, the key is 3, thie value is [number:0003, name:Claire, score:73, sex:female] the index is 3, the key is 4, Thie value is [number:0004, name:Amy, score:66, sex:male] // find 2={number=0002, name=Johnny, score=62, sex=female} // findAll [2:[number:0002, name:Johnny, score:62, sex:female], 3:[number:0003, name:Claire, score:73, sex:female], 4:[number:0004, name:Amy, score:66, sex:male]]] // count 1 // collect [Johnny, Claire, Amy] // groupBy [fail :[1:[number:0001, name:Bob, Score :55, sex:male]], groupBy :[2:[number:0002, name:Johnny, Score :62, sex:female], 3:[number:0003, name:Claire, score:73, sex:female], 4:[number:0004, name:Amy, score:66, Sex :male]]]] // Sort [1:[number:0001, name:Bob, Score :55, sex:male], 2:[number:0002, name:Johnny, Score :62, sex:female], 4:[number:0004, name:Amy, score:66, sex:male]], 3:[number:0003, name:Claire, score:73, sex:female]]Copy the code

Other:

  • When a map is defined, keys are usually defined as immutable strings or numbers.
  • Groovy defaults to treating strings that are not single quoted as immutable. (e.g. Red is the same as ‘red’)

Three, scope,

Range Definition, operation (each, switch-case)

def range = 1.10.           // Range is an interface that inherits from List, i.e. is essentially a List
println range[0]            // The first value of the range
println range.contains(10)  // Whether the range contains 10
println range.from          // The first value in the range
println range.to            // The last value in the range

/ / traverse
range.each {
  println it
}
for(i in range){
  println i
}

// switch-case
def getGrade(Number number){
  def result
  switch(number){
    case 0.. <60: / / [0, 60)
      result = 'Fail'
      break;
    case 60.. <70:
      result = 'pass'
      break;
    case 70.. <80:
      result = 'good'
      break;
    case 80.100.: / / [80, 100]
      result = 'good'
      break;
  }
  result // return result. You can omit the return here; the Groovy Chinese method returns the result of the last line by default
}

Copy the code

Groovy object Orientation

I. Definition and use of classes, interfaces, etc

// Class definition
class Person{
  String name
  
  Integer age // Int is the same as Integer. In Groovy, int is essentially Integer
  
  def increaseAge(Integer years){
    this.name += years
  }
}

// Create an object
def person = new Person(name: 'Lqr'.age: 18) // You can specify only one part, such as new Person(name: 'LQR ') or not specify it
println "the name is ${person.name}, the age is ${person.age}"
person.increaseAge(10)

// Interface definition
interface Action {
  void eat()
  void drink()
  void play()
}

// Trait class definitions (similar to abstract classes in Java)
trait DefaultAction {
  abstract void eat()
  void play(){
    println ' i can play.'}}Copy the code

conclusion

  • The default in Groovy is public (classes, member properties, methods, etc.)
  • Groovy classes inherit from groovy.lang.GroovyObject (whereas Java classes inherit from Object)
  • Def defines a method that returns Object
  • Groovy classes generate getters and setters for member variables by default.
  • Whether you call get/set directly, you end up calling get/set methods, such as Person.name equals Person.getName ().
  • The Groovy interface does not allow you to define non-public methods (e.g. Protected void eat()).

Metaprogramming

Groovy runtime class method call flow:

In Java, if an object calls a method that is not defined in a class, it will compile. In Groovy, however, the situation is different. At runtime, when an object calls a method that is not defined in a class, the metaClass method of the same name will be called. MethodMissing (String name, Object args) and invokeMethod(String name, Object args).

Define invokeMethod

When only the invokeMethod(String Name, Object args) method of the class is defined, the invokeMethod() is executed when the runtime calls a method of the Object that does not exist.

class Person{.// When a method cannot be found, call it instead
  def invokeMethod(String name, Object args){
    return "the method is ${name}, the params is ${args}"}}def person = new Person(name: 'Lqr'.age: 18)
person.cry()
Copy the code

Output:

the method is cry, the params is []
Copy the code

2. Define methodMissing

MethodMissing (String name, Object args) is preferred when both invokeMethod() and methodMissing() methods are defined in a class.

class Person{.// When a method cannot be found, call it instead
  def invokeMethod(String name, Object args){
    return "the method is ${name}, the params is ${args}"
  }
  
  def methodMissing(String name, Object args){
    return "the method ${name} is missing"}}def person = new Person(name: 'Lqr'.age: 18)
person.cry()
Copy the code

Output:

the method cry is missing
Copy the code

3, metaClass

MetaClass is the heart of metaprogramming in Groovy. In Groovy, you can use metaClass to dynamically add properties and methods to classes at run time

Useful for: Extending final classes in third-party libraries.

// Add an attribute to the class dynamically
Person.metaClass.sex = 'male' // Set the dynamic property sex to male by default
def Person = new Person(name: 'Lqr'.age: 18)
println person.sex
person.sex = 'female'
println "the new sex is:" + person.sex

// Dynamically add methods to the class
Person.metaClass.sexUpperCase = { -> sex.toUpperCase() }
def person2 = new Person(name: 'Lqr'.age: 18)
println person2.sexUpperCase()

// Add static methods to the class dynamically
Person.metaClass.static.createPerson = {
  String name, int age -> new Person(name: name, age: age)
}
def person3 = Person.createPerson('Lqr'.18)
println person3.name + ' and ' + person.age
Copy the code

Output:

Male the new sex is:female // Add static methods Lqr and 18 to classCopy the code

As you can see, Groovy’s metaClass is quite powerful, but it has one limitation that needs to be noted: By default, metaClass injected properties and methods are only transient (non-global, to be exact).

For example, in ClassA a Person is metaClass extended and dynamically injected properties and methods are called normally, but in ClassB it is not possible to use the previously dynamically injected properties and methods as well, because in Groovy metaClass dynamically injected properties and methods are non-global by default. You can do this in two ways:

  1. Use metaClass to dynamically inject properties and methods again in ClassB.
  2. Using the ExpandoMetaClass. EnableGlobally ().

4, ExpandoMetaClass. EnableGlobally ()

Using the ExpandoMetaClass. EnableGlobally () open the metaClass dynamic global injection properties, methods, functions.

/ / in ApplicationManager call ExpandoMetaClass. EnableGlobally (), and to extend the Person
class ApplicationManager{
  static void init(){
    ExpandoMetaClass.enableGlobally()
    // Add methods for third-party classes
    Person.metaClass.static.createPerson = { String name, int age ->
      new Person(name: name, age: age)
    }
  }
}

// The Person dynamically injected extension method is now available in ClassB
class ClassB{
  def test(){
    def person = Person.createPerson('Lqr'.18) CreatePerson (name: 'Lqr', age: 18) : createPerson(name: 'Lqr', age: 18);
    println "the person name is ${person.name} and the age is ${person.age}"}}// Entry simulates an App Entry
class Entry{
  static void main(String[] args){
    ApplicationManager.init()
    new ClassB().test()
  }
}
Copy the code

Output:

the person name is Lqr and the age is 18
Copy the code