Groovy

Личный сайт Go-разработчика из Казани

Groovy is a dynamic language for the Java platform

1/* 2 Set yourself up: 3 4 1) Install SDKMAN - http://sdkman.io/ 5 2) Install Groovy: sdk install groovy 6 3) Start the groovy console by typing: groovyConsole 7 8*/ 9 10// Single line comments start with two forward slashes 11/* 12Multi line comments look like this. 13*/ 14 15// Hello World 16println "Hello world!" 17 18/* 19 Variables: 20 21 You can assign values to variables for later use 22*/ 23 24def x = 1 25println x 26 27x = new java.util.Date() 28println x 29 30x = -3.1499392 31println x 32 33x = false 34println x 35 36x = "Groovy!" 37println x 38 39/* 40 Collections and maps 41*/ 42 43//Creating an empty list 44def technologies = [] 45 46// or create a list with data 47technologies = ["Kotlin", "Swift"] 48 49/*** Adding a elements to the list ***/ 50 51// As with Java 52technologies.add("Grails") 53 54// Left shift adds, and returns the list 55technologies << "Groovy" 56 57// Add multiple elements 58technologies.addAll(["Gradle","Griffon"]) 59 60/*** Removing elements from the list ***/ 61 62// As with Java 63technologies.remove("Griffon") 64 65// Subtraction works also 66technologies = technologies - 'Grails' 67 68/*** Iterating Lists ***/ 69 70// Iterate over elements of a list 71technologies.each { println "Technology: $it"} 72technologies.eachWithIndex { it, i -> println "$i: $it"} 73 74/*** Checking List contents ***/ 75 76//Evaluate if a list contains element(s) (boolean) 77contained = technologies.contains( 'Groovy' ) 78 79// Or 80contained = 'Groovy' in technologies 81 82// Check for multiple contents 83technologies.containsAll(['Groovy','Grails']) 84 85/*** Sorting Lists ***/ 86 87// Sort a list (mutates original list) 88technologies.sort() 89 90// To sort without mutating original, you can do: 91sortedTechnologies = technologies.sort( false ) 92 93/*** Manipulating Lists ***/ 94 95//Replace all elements in the list 96Collections.replaceAll(technologies, 'Gradle', 'gradle') 97 98//Shuffle a list 99Collections.shuffle(technologies, new Random()) 100 101//Clear a list 102technologies.clear() 103 104//Creating an empty map 105def devMap = [:] 106 107//Add values 108devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] 109devMap.put('lastName','Perez') 110 111//Iterate over elements of a map 112devMap.each { println "$it.key: $it.value" } 113devMap.eachWithIndex { it, i -> println "$i: $it"} 114 115//Evaluate if a map contains a key 116assert devMap.containsKey('name') 117 118//Evaluate if a map contains a value 119assert devMap.containsValue('Roberto') 120 121//Get the keys of a map 122println devMap.keySet() 123 124//Get the values of a map 125println devMap.values() 126 127/* 128 Groovy Beans 129 130 GroovyBeans are JavaBeans but using a much simpler syntax 131 132 When Groovy is compiled to bytecode, the following rules are used. 133 134 * If the name is declared with an access modifier (public, private or 135 protected) then a field is generated. 136 137 * A name declared with no access modifier generates a private field with 138 public getter and setter (i.e. a property). 139 140 * If a property is declared final the private field is created final and no 141 setter is generated. 142 143 * You can declare a property and also declare your own getter or setter. 144 145 * You can declare a property and a field of the same name, the property will 146 use that field then. 147 148 * If you want a private or protected property you have to provide your own 149 getter and setter which must be declared private or protected. 150 151 * If you access a property from within the class the property is defined in 152 at compile time with implicit or explicit this (for example this.foo, or 153 simply foo), Groovy will access the field directly instead of going though 154 the getter and setter. 155 156 * If you access a property that does not exist using the explicit or 157 implicit foo, then Groovy will access the property through the meta class, 158 which may fail at runtime. 159 160*/ 161 162class Foo { 163 // read only property 164 final String name = "Roberto" 165 166 // read only property with public getter and protected setter 167 String language 168 protected void setLanguage(String language) { this.language = language } 169 170 // dynamically typed property 171 def lastName 172} 173 174/* 175 Methods with optional parameters 176*/ 177 178// A method can have default values for parameters 179def say(msg = 'Hello', name = 'world') { 180 "$msg $name!" 181} 182 183// It can be called in 3 different ways 184assert 'Hello world!' == say() 185// Right most parameter with default value is eliminated first. 186assert 'Hi world!' == say('Hi') 187assert 'learn groovy!' == say('learn', 'groovy') 188 189/* 190 Logical Branching and Looping 191*/ 192 193//Groovy supports the usual if - else syntax 194def x = 3 195 196if(x==1) { 197 println "One" 198} else if(x==2) { 199 println "Two" 200} else { 201 println "X greater than Two" 202} 203 204//Groovy also supports the ternary operator: 205def y = 10 206def x = (y > 1) ? "worked" : "failed" 207assert x == "worked" 208 209//Groovy supports 'The Elvis Operator' too! 210//Instead of using the ternary operator: 211 212displayName = user.name ? user.name : 'Anonymous' 213 214//We can write it: 215displayName = user.name ?: 'Anonymous' 216 217//For loop 218//Iterate over a range 219def x = 0 220for (i in 0 .. 30) { 221 x += i 222} 223 224//Iterate over a list 225x = 0 226for( i in [5,3,2,1] ) { 227 x += i 228} 229 230//Iterate over an array 231array = (0..20).toArray() 232x = 0 233for (i in array) { 234 x += i 235} 236 237//Iterate over a map 238def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] 239x = "" 240for ( e in map ) { 241 x += e.value 242 x += " " 243} 244assert x.equals("Roberto Grails Groovy ") 245 246/* 247 Operators 248 249 Operator Overloading for a list of the common operators that Groovy supports: 250 http://www.groovy-lang.org/operators.html#Operator-Overloading 251 252 Helpful groovy operators 253*/ 254//Spread operator: invoke an action on all items of an aggregate object. 255def technologies = ['Groovy','Grails','Gradle'] 256technologies*.toUpperCase() // = to technologies.collect { it?.toUpperCase() } 257 258//Safe navigation operator: used to avoid a NullPointerException. 259def user = User.get(1) 260def username = user?.username 261 262 263/* 264 Closures 265 A Groovy Closure is like a "code block" or a method pointer. It is a piece of 266 code that is defined and then executed at a later point. 267 268 More info at: http://www.groovy-lang.org/closures.html 269*/ 270//Example: 271def clos = { println "Hello World!" } 272 273println "Executing the Closure:" 274clos() 275 276//Passing parameters to a closure 277def sum = { a, b -> println a+b } 278sum(2,4) 279 280//Closures may refer to variables not listed in their parameter list. 281def x = 5 282def multiplyBy = { num -> num * x } 283println multiplyBy(10) 284 285// If you have a Closure that takes a single argument, you may omit the 286// parameter definition of the Closure 287def clos = { print it } 288clos( "hi" ) 289 290/* 291 Groovy can memoize closure results 292*/ 293def cl = {a, b -> 294 sleep(3000) // simulate some time consuming processing 295 a + b 296} 297 298mem = cl.memoize() 299 300def callClosure(a, b) { 301 def start = System.currentTimeMillis() 302 mem(a, b) 303 println "Inputs(a = $a, b = $b) - took ${System.currentTimeMillis() - start} msecs." 304} 305 306callClosure(1, 2) 307callClosure(1, 2) 308callClosure(2, 3) 309callClosure(2, 3) 310callClosure(3, 4) 311callClosure(3, 4) 312callClosure(1, 2) 313callClosure(2, 3) 314callClosure(3, 4) 315 316/* 317 Expando 318 319 The Expando class is a dynamic bean so we can add properties and we can add 320 closures as methods to an instance of this class 321 322 http://mrhaki.blogspot.mx/2009/10/groovy-goodness-expando-as-dynamic-bean.html 323*/ 324 def user = new Expando(name:"Roberto") 325 assert 'Roberto' == user.name 326 327 user.lastName = 'Pérez' 328 assert 'Pérez' == user.lastName 329 330 user.showInfo = { out -> 331 out << "Name: $name" 332 out << ", Last name: $lastName" 333 } 334 335 def sw = new StringWriter() 336 println user.showInfo(sw) 337 338 339/* 340 Metaprogramming (MOP) 341*/ 342 343//Using ExpandoMetaClass to add behaviour 344String.metaClass.testAdd = { 345 println "we added this" 346} 347 348String x = "test" 349x?.testAdd() 350 351//Intercepting method calls 352class Test implements GroovyInterceptable { 353 def sum(Integer x, Integer y) { x + y } 354 355 def invokeMethod(String name, args) { 356 System.out.println "Invoke method $name with args: $args" 357 } 358} 359 360def test = new Test() 361test?.sum(2,3) 362test?.multiply(2,3) 363 364//Groovy supports propertyMissing for dealing with property resolution attempts. 365class Foo { 366 def propertyMissing(String name) { name } 367} 368def f = new Foo() 369 370assertEquals "boo", f.boo 371 372/* 373 TypeChecked and CompileStatic 374 Groovy, by nature, is and will always be a dynamic language but it supports 375 typechecked and compilestatic 376 377 More info: http://www.infoq.com/articles/new-groovy-20 378*/ 379//TypeChecked 380import groovy.transform.TypeChecked 381 382void testMethod() {} 383 384@TypeChecked 385void test() { 386 testMeethod() 387 388 def name = "Roberto" 389 390 println naameee 391 392} 393 394//Another example: 395import groovy.transform.TypeChecked 396 397@TypeChecked 398Integer test() { 399 Integer num = "1" 400 401 Integer[] numbers = [1,2,3,4] 402 403 Date date = numbers[1] 404 405 return "Test" 406 407} 408 409//CompileStatic example: 410import groovy.transform.CompileStatic 411 412@CompileStatic 413int sum(int x, int y) { 414 x + y 415} 416 417assert sum(2,5) == 7

Further resources

Groovy documentation

Groovy web console

Join a Groovy user group

Books