documentacion docs groovy

groovy - docs - grails documentation 2.4 4



¿Las características ocultas de Groovy? (30)

Deceleración de variables múltiples

1) Declaraciones de variables múltiples en una sola línea

def (a,b,c) = [1,2,3]

2) Usar diferentes tipos de declaraciones.

def (String a, int b) = [''Groovy'', 1]

Parece que Groovy fue olvidado en este hilo, así que solo haré la misma pregunta para Groovy.

  • Intenta limitar las respuestas al núcleo de Groovy
  • Una característica por respuesta
  • Dé un ejemplo y una breve descripción de la característica, no solo un enlace a la documentación
  • Etiquete la función usando el título en negrita como primera línea

Ver también:

  1. Funciones ocultas de Python
  2. Características ocultas de Ruby
  3. Características ocultas de Perl
  4. Funciones ocultas de Java

Operador de coerción

El operador de coerción (as) es una variante del casting. La coerción convierte objetos de un tipo a otro sin que sean compatibles para la asignación. Tomemos un ejemplo:

Entero x = 123
Cadena s = (Cadena) x
El entero no es asignable a una Cadena, por lo que producirá una ClassCastException en tiempo de ejecución. Esto se puede solucionar mediante el uso de la coerción:

Entero x = 123 cadena s = x como cadena
El entero no es asignable a una Cadena, pero el uso de lo forzará a una Cadena.


¿Cómo construir un árbol JSON en un par de líneas en groovy?

1) defina su árbol con autorreferencial withDefault cierre withDefault

def tree // declare first before using a self reference tree = { -> [:].withDefault{ tree() } }

2) Crea tu propio árbol JSON

frameworks = tree() frameworks.grails.language.name = ''groovy'' frameworks.node.language.name = ''js'' def result = new groovy.json.JsonBuilder(frameworks)

Que da: {"grails":{"language":{"name":"groovy"}},"node":{"language":{"name":"js"}}}


A diferencia de Java, en Groovy, cualquier cosa se puede usar en una sentencia switch , no solo en tipos primitivos. En un evento típico Método informado

switch(event.source) { case object1: // do something break case object2: // do something break }


Alguien sabe sobre Elvis ?

def d = "hello"; def obj = null; def obj2 = obj ?: d; // sets obj2 to default obj = "world" def obj3 = obj ?: d; // sets obj3 to obj (since it''s non-null)


Averiguar qué métodos hay en un objeto es tan fácil como preguntarle a metaClass:

"foo".metaClass.methods.name.sort().unique()

huellas dactilares:

["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo", "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", "endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars", "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", "notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", "replaceAll", "replaceFirst", "split", "startsWith", "subSequence", "substring", "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]


Creo que es una combinación de cierres como parámetro y parameter-default-values:

public void buyItems(Collection list, Closure except={it > 0}){ list.findAll(){except(it)}.each(){print it} } buyItems([1,2,3]){it > 2} buyItems([0,1,2])

impresiones: "312"


El método with permite activar esto:

myObj1.setValue(10) otherObj.setTitle(myObj1.getName()) myObj1.setMode(Obj1.MODE_NORMAL)

dentro de esto

myObj1.with { value = 10 otherObj.title = name mode = MODE_NORMAL }


Eliminar valores null de la lista

def list = [obj1, obj2, null, obj4, null, obj6] list -= null assert list == [obj1, obj2, obj4, obj6]


En Groovy 1.6, las expresiones regulares funcionan con todos los iteradores de cierre (como cada uno, recopilar, inyectar, etc.) y te permiten trabajar fácilmente con los grupos de captura:

def filePaths = """ /tmp/file.txt /usr/bin/dummy.txt """ assert (filePaths =~ /(.*)//(.*)/).collect { full, path, file -> "$file -> $path" } == ["file.txt -> /tmp", "dummy.txt -> /usr/bin"]


Groovy puede funcionar mucho como Javascript. Puede tener vars privados y funciones a través del cierre. También puede curry funciones con cierres.

class FunctionTests { def privateAccessWithClosure = { def privVar = ''foo'' def privateFunc = { x -> println "${privVar} ${x}"} return {x -> privateFunc(x) } } def addTogether = { x, y -> return x + y } def curryAdd = { x -> return { y-> addTogether(x,y)} } public static void main(String[] args) { def test = new FunctionTests() test.privateAccessWithClosure()(''bar'') def curried = test.curryAdd(5) println curried(5) } }

salida:

foo bar 10


La reordenación de argumentos con argumentos implícitos es otra muy buena.

Este código:

def foo(Map m=[:], String msg, int val, Closure c={}) { [...] }

Crea todos estos métodos diferentes:

foo("msg", 2, x:1, y:2) foo(x:1, y:2, "blah", 2) foo("blah", x:1, 2, y:2) { [...] } foo("blah", 2) { [...] }

Y más. Es imposible equivocarse al poner los argumentos nominales y ordinales en el orden / posición incorrectos.

Por supuesto, en la definición de "foo", puede dejar "String" e "int" desde "String msg" e "int val" - Los dejé para mayor claridad.


Las características proporcionadas por las transformaciones dentro del paquete groovy.transform de GDK, tales como:

  • @Immutable : la anotación @Imutable instruye al compilador a ejecutar una transformación AST que agrega los captadores, constructores, iguales, hashCode y otros métodos auxiliares necesarios que se escriben normalmente al crear clases inmutables con las propiedades definidas.
  • @CompileStatic : Esto permitirá que el compilador de Groovy use comprobaciones de tiempo de compilación en el estilo de Java y luego realice una compilación estática, omitiendo así el protocolo de objeto meta de Groovy.
  • @Canonical : la anotación @Canonical instruye al compilador para que ejecute una transformación AST que añada constructores posicionales, equals, hashCode y una bonita letra toString a su clase.

Otros:

  • @Slf4j Esta transformación local agrega una capacidad de registro a su programa mediante el registro LogBack. Cada llamada de método en una variable independiente llamada registro se asignará a una llamada al registrador.
  • Groovy''s XML Slurper : análisis sencillo de XML. Característica asesina!

Los cierres pueden hacer desaparecer todos los antiguos juegos de gestión de recursos. La secuencia de archivos se cierra automáticamente al final del bloque:

new File("/etc/profile").withReader { r -> System.out << r }


Para interceptar los métodos estáticos faltantes, use la siguiente

Foo { static A() { println "I''m A"} static $static_methodMissing(String name, args) { println "Missing static $name" } } Foo.A() //prints "I''m A" Foo.B() //prints "Missing static B"

- Ken


Para probar el código de Java con Groovy, el generador de gráficos de objetos es sorprendente:

def company = builder.company( name: ''ACME'' ) { address( id: ''a1'', line1: ''123 Groovy Rd'', zip: 12345, state: ''JV'' ) employee( name: ''Duke'', employeeId: 1 ){ address( refId: ''a1'' ) } }

Característica estándar, pero aún muy agradable.

ObjectGraphBuilder

(No necesita dar ninguna propiedad de su POJO que sea un valor predeterminado de la lista de una lista vacía en lugar de null para que funcione el soporte del constructor).


Puede convertir una lista en un mapa utilizando toSpreadMap (), conveniente cuando la orden en la lista sea suficiente para determinar las claves y los valores asociados a ellas. Vea el ejemplo a continuación.

def list = [''key'', ''value'', ''foo'', ''bar''] as Object[] def map = list.toSpreadMap() assert 2 == map.size() assert ''value'' == map.key assert ''bar'' == map[''foo'']


Sé que estoy un poco tarde, pero creo que faltan algunas buenas características aquí:

Operadores de recolección más / menos

def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9) assert l == [1, 4, 6, 7, 8, 9] def m = [a: 1, b: 2] + [c: 3] - [a: 1] assert m == [b: 2, c: 3]

Declaración de cambio

switch (42) { case 0: .. break case 1..9: .. break case Float: .. break case { it % 4 == 0 }: .. break case ~//d+/: .. break }

Rangos e indexación

assert (1..10).step(2) == [1, 3, 5, 7, 9] assert (1..10)[1, 4..8] == [2, 5, 6, 7, 8, 9] assert (''a''..''g'')[-4..-2] == [''d'', ''e'', ''f'']

Nombres de variables Unicode

def α = 123 def β = 456 def Ω = α * β assert Ω == 56088


Usar hashes como pseudo-objetos.

def x = [foo:1, bar:{-> println "Hello, world!"}] x.foo x.bar()

Combinado con el tipado de patos, puede recorrer un largo camino con este enfoque. Ni siquiera es necesario sacar al operador "como".


@Delegate

class Foo { def footest() { return "footest"} } class Bar { @Delegate Foo foo = new Foo() } def bar = new Bar() assert "footest" == bar.footest()


Destructuring

Podría ser llamado algo más en Groovy; se llama desestructuración en clojure. Nunca creerás cuán útil puede venir.

def list = [1, ''bla'', false] def (num, str, bool) = list assert num == 1 assert str == ''bla'' assert !bool


Implementación de Interfaz Basada en Cierre

Si tiene una referencia tipeada como:

MyInterface foo

Puede implementar toda la interfaz usando:

foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface

Alternativamente, si desea implementar cada método por separado, puede usar:

foo = [bar: {-> println "bar invoked"}, baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface


Invocación de método dinámico

Puede invocar un método usando una cadena con su nombre

class Dynamic { def one() { println "method one()" } def two() { println "method two()" } } def callMethod( obj, methodName ) { obj."$methodName"() } def dyn = new Dynamic() callMethod( dyn, "one" ) //prints ''method one()'' callMethod( dyn, "two" ) //prints ''method two()'' dyn."one"() //prints ''method one()''


Memoization

La memorización es una técnica de optimización que consiste en almacenar los resultados de llamadas a funciones costosas y devolver el resultado en caché cada vez que se vuelve a llamar a la función con los mismos argumentos.

Hay una versión ilimitada, que almacenará en caché cada par de (argumentos de entrada, valor de retorno) que alguna vez verá; y una versión limitada, que almacenará en caché los últimos N argumentos de entrada vistos y sus resultados, utilizando un caché LRU.

Memoración de métodos:

import groovy.transform.Memoized @Memoized Number factorial(Number n) { n == 0 ? 1 : factorial(n - 1) } @Memoized(maxCacheSize=1000) Map fooDetails(Foo foo) { // call expensive service here }

Memoración de cierres:

def factorial = {Number n -> n == 0 ? 1 : factorial(n - 1) }.memoize() fooDetails = {Foo foo -> // call expensive service here }.memoizeAtMost(1000)

La página de Wikipedia tiene amplia información sobre los usos de la Memoización en Ciencias de la Computación. Solo señalaré un uso práctico simple.

Aplazar la inicialización de una constante al último momento posible

Algunas veces tiene un valor constante que no se puede inicializar en la definición de la clase o el tiempo de creación. Por ejemplo, la expresión constante puede hacer uso de otra constante o un método de una clase diferente, que será conectada por otra cosa (Spring o similar) después de la inicialización de su clase.

En este caso, puede convertir su constante en un getter y decorarlo con @Memoized . Solo se computará una vez, la primera vez que se acceda, y luego el valor almacenado en caché y reutilizado:

import groovy.transform.Memoized @Memoized def getMY_CONSTANT() { // compute the constant value using any external services needed }


Operador de navegación segura

El operador Safe Navigation se usa para evitar una NullPointerException. Normalmente, cuando tiene una referencia a un objeto, es posible que necesite verificar que no sea nulo antes de acceder a los métodos o las propiedades del objeto. Para evitar esto, el operador de navegación segura simplemente devolverá nulo en lugar de lanzar una excepción, así:

def person = Person.find { it.id == 123 } // find will return a null instance def name = person?.name // use of the null-safe operator prevents from a NullPointerException, result is null


Subrayar en literales

Cuando se escriben números literales largos, es más difícil entender cómo se agrupan algunos números, por ejemplo, con grupos de miles, de palabras, etc. Al permitir colocar guiones bajos en literales numéricos, es más fácil detectar esos grupos:

long creditCardNumber = 1234_5678_9012_3456L long socialSecurityNumbers = 999_99_9999L double monetaryAmount = 12_345_132.12 long hexBytes = 0xFF_EC_DE_5E long hexWords = 0xFFEC_DE5E long maxLong = 0x7fff_ffff_ffff_ffffL long alsoMaxLong = 9_223_372_036_854_775_807L long bytes = 0b11010010_01101001_10010100_10010010


Usando el operador de nave espacial

Me gusta el operador de nave espacial , útil para todo tipo de escenarios de clasificación personalizados. Algunos ejemplos de uso están here . Una situación en la que es particularmente útil es crear un comparador sobre la marcha de un objeto usando múltiples campos. p.ej

def list = [ [ id:0, first: ''Michael'', last: ''Smith'', age: 23 ], [ id:1, first: ''John'', last: ''Smith'', age: 30 ], [ id:2, first: ''Michael'', last: ''Smith'', age: 15 ], [ id:3, first: ''Michael'', last: ''Jones'', age: 15 ], ] // sort list by last name, then first name, then by descending age assert (list.sort { a,b -> a.last <=> b.last ?: a.first <=> b.first ?: b.age <=> a.age })*.id == [ 3,1,0,2 ]


Usando el operador de puntos extendidos

def animals = [''ant'', ''buffalo'', ''canary'', ''dog''] assert animals.size() == 4 assert animals*.size() == [3, 7, 6, 3]

Este es un atajo para animals.collect { it.size() } .


Usar el operador spread en los parámetros del método

Esto es de gran ayuda al convertir código a datos:

def exec(operand1,operand2,Closure op) { op.call(operand1,operand2) } def addition = {a,b->a+b} def multiplication = {a,b->a*b} def instructions = [ [1,2,addition], [2,2,multiplication] ] instructions.each{instr-> println exec(*instr) }

También es útil este uso:

String locale="en_GB" //this invokes new Locale(''en'',''GB'') def enGB=new Locale(*locale.split(''_''))


println """ Groovy has "multi-line" strings. Hooray! """