Lenguaje Groovy

  • Es un lenguaje que utiliza la máquina virtual de Java.
  • Es un lenguaje dinámico (al igual de lo que pasa con Javascript, nos permite añadir propiedades dinámicamente y el tipado de las variables es opcional)
  • Tiene una sintaxis muy concisa, fácil de aprender y similar a Java, que nos permite ser más productivos ya que nos permite hacer mucho más con menos código.
  • Podemos poner códigos de Groovy en un documento Java ( siempre que importemos el compilador).
  • Puedes utilizar código Java en Groovy.
  • Permite compilar en tiempo de ejecución ( modificaciones en caliente).
  • En Groovy, por defecto, las clases y los métodos son públicos.
  • Internamente, se generarán los getters y los setters de todas los atributos, y será utilizados utilizando una sintaxis similar a cuando llamamos a una propiedad.
persona.nombre = "Juan"

De esta forma estamos accediendo al getter del objeto, por lo que podemos omitir el modificador private de la propiedad porque de todas formas no vamos a poder acceder a ella directamente.

  • La última línea de todos los métodos que devuelven algo siempre es un return. Por tanto, podemos omitir el return e igualmente se ejecutará.
  • Podemos llamar a System.out.println escribiendo simplemente println.
  • Por cada clase, además del constructor vacío, se crean varios constructores, con todas las combinaciones posibles de atributos que tiene la clase. Podremos alimentar dichos constructores con un mapa.
  • Es indiferente usar comillas simples o dobles.
  • Los paréntesis de los métodos son opcionales.
  • El método que está fuera de la clase es automáticamente el public static void main.
  • Todas las excepciones son unchecked.
  • Es un Java con esteroides.

Crear un proyecto de consola con Groovy

Utilizaremos la versión Community de IntelliJ.

Para poder hacer aplicaciones de consola con Groovy, necesitaremos descargar el gdk de la página de Apache. En el caso de que querramos hacer una aplicación de servidor con Grails, las librerías de Groovy ya están integradas y este paso no sería necesario.

Ejercicio Hola Mundo

1. Crea un proyecto con Groovy.

2. Crea una clase Groovy.

3. Ejecuta el siguiente código.

println 'hello World!'

POGO en Groovy

class Persona {
    String nombre
    int edad
}

No hace falta que en el POGO cree el constructor. Las clases de Groovy tienen por defecto el named constructor, que me permite pasar al constructor de la clase un mapa con los nombres y valores de los atributos que desee inicializar.

def p = new Persona(nombre:'Paco')
println(p.nombre)

Dentro del println, nombre es una forma abreviada de llamar al método getNombre() del objeto p.

Otra forma de hacer lo mismo de antes:

(Existe, pero nunca la he utilizado).

@Builder
class Persona {
    String nombre
    int edad
}
def p2 = Persona.builder().nombre('Paco').edad(37).build()

Interpolación de cadenas

En Groovy, cuando haces un String, realmente estás haciendo un GString.

String nombre = 'Juan'
println 'Mi nombre es ${nombre}'

Colecciones

Listas

Crear una lista

def myList = ['a', 'b', 'c']
println myList

Añadir elementos a una lista

myList.add('d')
myList << 'e' //esta línea es equivalente a la anterior

Recorrer una lista

println myList.collect{ e -> e.toUpperCase()}

Si no le damos un nombre al objeto que representa a cada uno de los elementos de la lista, dicho objeto se llamará it.

println myList.collect{ it.toUpperCase()}

Mapas

def myMap = [valor1:1, valor2:2]
println myMap
myMap.valor3 = 3
myMap['valor4'] = 'valor4'

println myMap.collect{ it.toUpperCase()}

println myMap.collect{ e -> e.toUpperCase()}

Rangos

def myRange = 3..8
/*
Otros ejemplos de rango:
'a'..'h'
3..<8 (el ocho exclusive)
8..3
*/

println myRange[0] // 3
println myRange[-1] // 8 (poniendo un menos delante, empezaremos la lista por el final)

Groovy vs Java

Saludador.java

public class Saludador {
    private String saludo;

    public void setSaludo(String saludo){
        this.saludo=saludo;
    }

    public String getSaludo(){
        return this.saludo;
    }

    public void diHolaA(String... nombres){
        String mensajeSaludo=prepararMensajeSaludo(nombres);
        System.out.println(mensajeSaludo);
    }

    public String prepararMensajeSaludo(String... nombres){
        String delimitador="";
        StringBuilder sb=new StringBuilder();
        for(String nombre: nombres){
            sb.append(delimitador).append(nombre);
            delimitador=", ";
        }
        return this.saludo+" "+sb.toString()+"!";
    }

    public static void main(String[] args){
        final Saludador saludador=new Saludador();
        saludador.setSaludo("Hola");
        saludador.diHolaA("Pablo", "Alex", "Conde Bracula", "Hombre del saco");
    }
}

Saludador.groovy

class Saludador {
    String saludo

    void diHolaA(String... nombres){
       println "${this.saludo} ${nombres.join(', ')}!"
    }
}
final Saludador saludador=new Saludador(saludo: "Hola")
saludador.diHolaA "Pablo", "Alex", "Conde Bracula", "Hombre del saco"

Operador *

Nos permite acceder a todos los elementos de una lista.

def saludos=[new Saludador(saludo:'hola'), new Saludador(saludo: 'hello')]
println saludos*.saludo

Booleanos

En Groovy, todas las variables, independientemente de su tipo, tienen un valor booleano implícito (Groovy Truth).

def variableNula = null
if( variableNula){
    println 'variableNula es verdad'
}else{
    println 'variableNula es falso'
}

def cadenaVacia = ''
if( cadenaVacia){
    println 'cadenaVacia es verdad'
}else{
    println 'cadenaVacia es falso'
}

También son falsas las listas vacías, los mapas vacíos, y el número cero. En contraposición a esto, todo lo contrario a esto, será verdad.

Elvis Operator

Es una versión acortada del operador ternario de java para el caso de uso más típico de dicho operador que consiste en evaluar si una variable tiene valor, si lo tiene, nos quedamos con él, y si no, le asignamos un valor alternativo.

def nombres = []
// Java form
List resultado = ( nombres != null && nombres.size() > 0 ) ? nombres : Collections.emptyList();

// Usando la verdad de Groovy
def resultado2 = nombres ? nombres : []

// Usando el Elvis operator
def resultado3 = nombres ?: []

Se llama elvis operator porque si giras la cabeza dejando la interrogación arriba, parece el tupé de Elvis.

Null Safe operator o Safe navigation

def pedido = new Pedido( id: 1, cliente: new Cliente(nombre: 'Paco', direccion: new Direccion(calle:'Camino de Rubin')))

// Versión Java
if(pedido != null){
    if (pedido.cliente != null){
        if( pedido.cliente.direccion != null){
            println pedido.cliente.direccion.calle
        }
    }
}

// Versión Groovy
println pedido?.cliente?.direccion?.calle

Closures

def multiplicador = { a, b -> a*b}
println multiplicador( 2,3 ) // 6
println multiplicador( 'x',3 ) // xxx

def multiplicador2 = { a, b=10 -> a*b}
println multiplicador2( 2 ) // 20


def sumador = { ...numeros -> numeros.sum() }
println sumador(2,3,4)

Closures para listas

def personas = [ new Persona(nombre:"Paco", edad:15), new Persona(nombre:"Juan", edad:20), new Persona(nombre:"Laura", edad:50)]

def paco = personas.find{it.nombre == 'Paco'}
println paco.nombre

def personasMayores18 = personas.findAll{it.edad > 18}
println personasMayores18

// El collect aplica la operación que hay dentro del closure a todos los elmentos de una lista
def personasMayores18EnMayusculas = personas.findAll{it.edad > 18}.collect{it.nombre.toUpperCase()}
println personasMayores18EnMayusculas

def personasOrdenadas = personas.collect{it.nombre.toUpperCase()}.sort()
println personasOrdenadas

// El * significa: para cada objeto de esta lista
def nombres = personas*.nombre
print nombres

def nombresOrdenadosPorLongitud = personas.sort{it.nombre.size()}
println nombresOrdenadosPorLongitud

def personasOrdenadasPorLongitudDeNombre = personas*.nombre.sort{it.size()}
println personasOrdenadasPorLongitudDeNombre

Leer ficheros

def contenido = new File('data.txt').text
print contenido

def contenidoWeb = 'https://pablomonteserin.com'.toURL().text
print contenidoWeb