- 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