Translate

Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas

lunes, 17 de febrero de 2025

Pattern matching para instanceof en Java


Pattern matching para instanceof es una característica introducida en Java 14 como una mejora para escribir código más conciso y seguro al realizar comprobaciones de tipo y conversiones.

Antes de Java 14, verificar si un objeto era de cierto tipo y luego convertirlo requería código repetitivo:


if (obj instanceof String) {

    String str = (String) obj;

    System.out.println("Longitud: " + str.length());

}


La coincidencia de patrones para `instanceof` elimina la necesidad del casting explícito, reduciendo la repetición:


if (obj instanceof String str) {

    System.out.println("Longitud: " + str.length());

}


La coincidencia de patrones se puede usar en estructuras más complejas como `else if`:


public void imprimir(Object obj) {

    if (obj instanceof String str) {

        System.out.println("Es un String: " + str);

    } else if (obj instanceof Integer num) {

        System.out.println("Es un Integer: " + num);

    } else {

        System.out.println("Tipo desconocido");

    }

}


La variable resultante solo está disponible dentro del bloque if, lo que evita posibles accesos indebidos:


if (obj instanceof String str) {

    System.out.println(str.length()); // Válido

}

System.out.println(str); // Error: No está definido fuera del if


La coincidencia de patrones para instanceof simplifica la escritura de código en Java, haciéndolo más expresivo y seguro. Esta funcionalidad es el primer paso hacia mejoras más avanzadas en la manipulación de tipos en el lenguaje.


Lombok @Builder: Simplificando la Creación de Objetos en Java


En el blog nunca he hablado de lombok, porque no me gusta que exista un framework que haga lo que tendria que tener el lenguaje que programamos. Pero esta funcionalidad de lombok no la conocia y me esta buena. 

La creación de objetos con múltiples atributos puede volverse tediosa y propensa a errores si se usa el enfoque tradicional de constructores o setters. Lombok ofrece la anotación @Builder, que es una solución elegante que permite generar automáticamente un patrón de construcción de objetos de manera fluida y legible.

Lombok es una librería que reduce el código repetitivo en Java mediante anotaciones que generan automáticamente métodos como getter, setter, equals, hashCode y toString. Una de sus anotaciones más útiles es @Builder, que facilita la creación de objetos sin necesidad de escribir constructores manualmente.

Para agregar Lombok, si usas Maven, agrega la siguiente dependencia:


<dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

    <version>1.18.26</version>

    <scope>provided</scope>

</dependency>


Si usas Gradle:


dependencies {

    compileOnly 'org.projectlombok:lombok:1.18.26'

    annotationProcessor 'org.projectlombok:lombok:1.18.26'

}


Veamos un ejemplo de una clase que tiene un builder: 


import lombok.Builder;

import lombok.Getter;

import lombok.ToString;


@Getter

@ToString

@Builder

public class Usuario {

    private String nombre;

    private String email;

    private int edad;

}

public class Main {

    public static void main(String[] args) {

        Usuario usuario = Usuario.builder()

                .nombre("Juan Pérez")

                .email("juan.perez@example.com")

                .edad(30)

                .build();

        

        System.out.println(usuario);

    }

}


Se puede personalizar el constructor y el nombre del método de construcción con @Builder, veamos un ejemplo :


@Builder(builderMethodName = "nuevoUsuario")

public class Usuario {

    private String nombre;

    private String email;

    private int edad;

}


Uso:


Usuario usuario = Usuario.nuevoUsuario()

        .nombre("Ana López")

        .email("ana.lopez@example.com")

        .edad(28)

        .build();


El uso de @Builder en Lombok simplifica la creación de objetos en Java, haciendo que el código sea más conciso, flexible y fácil de mantener. Esta anotación es especialmente útil cuando se manejan objetos con múltiples atributos opcionales, evitando la necesidad de escribir múltiples constructores sobrecargados.


Dejo link:

https://www.baeldung.com/lombok-builder

sábado, 15 de febrero de 2025

Record en Java


Con la introducción de los records en Java 14 como una feature en vista previa y su estandarización en Java 16, ahora es más fácil crear clases inmutables de manera concisa y sin la sobrecarga de escribir código repetitivo.

Un record es una clase especial diseñada para almacenar datos de manera inmutable. Se encarga automáticamente de generar los métodos equals(), hashCode(), toString() y los accesores (`getters`) sin necesidad de escribir código adicional.

Veamos un ejemplo: 


public record Usuario(String nombre, String email, int edad) {}


La declaración anterior equivale a escribir lo siguiente en una clase tradicional:


public final class Usuario {

    private final String nombre;

    private final String email;

    private final int edad;

    

    public Usuario(String nombre, String email, int edad) {

        this.nombre = nombre;

        this.email = email;

        this.edad = edad;

    }

    

    public String nombre() { return nombre; }

    public String email() { return email; }

    public int edad() { return edad; }

    

    @Override

    public boolean equals(Object o) { /* Implementación automática */ }

    

    @Override

    public int hashCode() { /* Implementación automática */ }

    

    @Override

    public String toString() { /* Implementación automática */ }

}


Veamos como usar un record: 


public class Main {

    public static void main(String[] args) {

        Usuario usuario = new Usuario("Juan Pérez", "juan.perez@example.com", 30);       

        System.out.println(usuario);

    }

}


Salida:

Usuario[nombre=Juan Pérez, email=juan.perez@example.com, edad=30]


Se puede agregar métodos adicionales si es necesario:


public record Usuario(String nombre, String email, int edad) {

    public boolean esMayorDeEdad() {

        return edad >= 18;

    }

}


Los record en Java son una herramienta poderosa para definir estructuras de datos inmutables de forma concisa y eficiente. Gracias a ellos, el código es más limpio, menos propenso a errores y más fácil de mantener.


jueves, 13 de febrero de 2025

AssertJ


En el mundo de las pruebas unitarias en Java, AssertJ se ha consolidado como una de las herramientas más poderosas y expresivas para realizar aserciones. Este framework proporciona una API fluida y altamente legible que facilita la validación de resultados en las pruebas, mejorando la mantenibilidad y claridad del código.

AssertJ es una librería de aserciones para Java con una API expresiva y encadenable. Entre sus principales características se encuentran:

  • Sintaxis fluida y encadenada.
  • Mejor manejo de colecciones y excepciones.
  • Comparaciones avanzadas con objetos y fechas.
  • Integración con JUnit y TestNG.

Para utilizar AssertJ en un proyecto Maven, agrega la siguiente dependencia:


<dependency>

    <groupId>org.assertj</groupId>

    <artifactId>assertj-core</artifactId>

    <version>3.24.2</version>

    <scope>test</scope>

</dependency>



Si usas Gradle:

testImplementation 'org.assertj:assertj-core:3.24.2'


Veamos  un ejemplo de cómo realizar aserciones básicas con AssertJ:



import static org.assertj.core.api.Assertions.*;

import org.junit.jupiter.api.Test;


class AssertJExampleTest {

    @Test

    void testBasicAssertions() {

        String mensaje = "Hola AssertJ";

        assertThat(mensaje)

            .isNotNull()

            .startsWith("Hola")

            .endsWith("AssertJ")

            .contains("AssertJ");

    }

}


Otro ejemplo: 

@Test

void testNumbers() {

    int resultado = 10;

    assertThat(resultado)

        .isPositive()

        .isGreaterThan(5)

        .isLessThanOrEqualTo(10);

}


@Test

void testListAssertions() {

    List<String> nombres = List.of("Juan", "Maria", "Carlos");

    assertThat(nombres)

        .hasSize(3)

        .contains("Maria")

        .doesNotContain("Pedro")

        .containsExactly("Juan", "Maria", "Carlos");

}


Veamos Aserciones con Excepciones:


@Test

void testException() {

    assertThatThrownBy(() -> {

        throw new IllegalArgumentException("Error de prueba");

    }).isInstanceOf(IllegalArgumentException.class)

      .hasMessageContaining("Error");

}


AssertJ es una excelente opción para mejorar las pruebas unitarias en Java, ofreciendo una API intuitiva y potente que facilita la validación de resultados. Su uso ayuda a escribir pruebas más claras y mantenibles, mejorando la calidad del código.


Dejo link: https://www.baeldung.com/introduction-to-assertj

lunes, 10 de febrero de 2025

Bloques de Texto en Java


Con la introducción de los Bloques de Texto en Java 13 y su estandarización en Java 15, la manipulación de cadenas multilínea se ha vuelto mucho más sencilla y legible. Esta característica permite definir textos sin necesidad de escapar caracteres especiales o concatenar múltiples líneas, lo que mejora la claridad del código.

Los bloques de texto son literales de cadena que pueden abarcar múltiples líneas, definidos usando tres comillas dobles ("""). Se utilizan para escribir fragmentos de texto extensos sin necesidad de concatenaciones o caracteres de escape innecesarios.

Antes de los bloques de texto, una cadena multilínea en Java debía escribirse así:

String json = "{\n" +

              "    \"nombre\": \"Juan\",\n" +

              "    \"edad\": 25\n" +

              "}";

Con los bloques de texto, el mismo código se simplifica de la siguiente manera:


String json = """

    {

        "nombre": "Juan",

        "edad": 25

    }

    """;


Los bloques de texto son especialmente útiles en consultas SQL y plantillas HTML. Por ejemplo:


String query = """

    SELECT * FROM usuarios

    WHERE edad > 18

    ORDER BY nombre;

    """;


Otro ejemplo con HTML:


String html = """

    <html>

        <body>

            <h1>Bienvenido</h1>

        </body>

    </html>

    """;

Java mantiene la indentación de los bloques de texto, pero puedes usar `stripIndent()` para eliminar espacios innecesarios.

Puedes utilizar formatted() para reemplazo de valores dinámicos dentro del bloque.

Los bloques de texto en Java ofrecen una solución elegante para manejar cadenas multilínea de forma clara y eficiente. Su uso simplifica la lectura y escritura de código, mejorando la productividad de los desarrolladores.


martes, 4 de febrero de 2025

Haciendo fácil el calculo de hashing en archivoa con java.security.MessageDigest


Java 12 introdujo una API que facilita el cálculo de resúmenes de archivos (hashing) de manera eficiente y sencilla mediante la clase java.security.MessageDigest. Esta API permite generar hashes de archivos utilizando algoritmos como SHA-256 o MD5 sin necesidad de manejar manualmente la lectura de bytes y el procesamiento del hash.

Un hash de archivo es un valor único derivado de su contenido, generado por una función hash criptográfica. Es ampliamente utilizado para:

  • Verificar la integridad de archivos.
  • Comparar grandes volúmenes de datos de manera eficiente.
  • Validar la autenticidad de descargas.

Java 12 simplificó el proceso de generación de hash de archivos mediante el uso de `MessageDigest` junto con `Files.newInputStream`.

Veamos un ejemplo de uso con SHA-256:


import java.io.IOException;

import java.nio.file.Files;

import java.nio.file.Path;

import java.security.DigestInputStream;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

import java.util.HexFormat;


public class FileHashingExample {

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {

        Path filePath = Path.of("archivo.txt");

        

        String hash = calculateFileHash(filePath, "SHA-256");

        System.out.println("Hash SHA-256: " + hash);

    }

    

    public static String calculateFileHash(Path path, String algorithm) throws IOException, NoSuchAlgorithmException {

        MessageDigest digest = MessageDigest.getInstance(algorithm);

        

        try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(path), digest)) {

            while (dis.read() != -1) { } // Leer completamente el archivo

        }

        

        byte[] hashBytes = digest.digest();

        return HexFormat.of().formatHex(hashBytes);

    }

}


Otra mejora en Java 12 es el método Files.mismatch, que permite comparar dos archivos y determinar la primera posición donde difieren. Esto es útil para verificaciones de integridad.


import java.nio.file.Files;

import java.nio.file.Path;

import java.io.IOException;


public class FileComparisonExample {

    public static void main(String[] args) throws IOException {

        Path file1 = Path.of("archivo1.txt");

        Path file2 = Path.of("archivo2.txt");

        

        long mismatch = Files.mismatch(file1, file2);

        

        if (mismatch == -1) {

            System.out.println("Los archivos son idénticos.");

        } else {

            System.out.println("Los archivos difieren en la posición: " + mismatch);

        }

    }

}


Esta API facilita el cálculo de hashes y la comparación de archivos, mejorando la eficiencia y seguridad del procesamiento de datos. Estas mejoras hacen que Java sea una opción aún más atractiva para tareas de integridad de archivos y validación criptográfica.


domingo, 2 de febrero de 2025

Procesamiento simultáneo de datos con Streams gracias a colectores de Teeing en Java


Java 12 introdujo una nueva funcionalidad en la API de Streams: el colector teeing, el cual permite combinar dos colectores en una sola operación y fusionar sus resultados en un solo valor. Esta característica proporciona una forma elegante y eficiente de realizar dos operaciones de recolección en paralelo sobre un mismo flujo de datos.

El colector teeing se encuentra en la clase Collectors y permite procesar un Stream<T> en dos colectores distintos. Luego, combina los resultados mediante una función de fusión.

El metodo sería el siguiente: 


public static <T, R1, R2, R> Collector<T, ?, R> teeing(

    Collector<? super T, ?, R1> downstream1,

    Collector<? super T, ?, R2> downstream2,

    BiFunction<? super R1, ? super R2, R> merger)


Los parametros son: 

- downstream1: Primer colector que procesará el flujo de datos.

- downstream2: Segundo colector que operará sobre el mismo flujo.

- merger: Función que combina los resultados de ambos colectores en un solo valor.


Supongamos que queremos calcular simultáneamente el promedio y el mínimo de una lista de números.


import java.util.List;

import java.util.stream.Collectors;


public class TeeingExample {

    public static void main(String[] args) {

        List<Integer> numbers = List.of(3, 5, 7, 2, 8, 10);

        

        var result = numbers.stream().collect(

            Collectors.teeing(

                Collectors.averagingDouble(i -> i),

                Collectors.minBy(Integer::compareTo),

                (average, min) -> "Promedio: " + average + ", Mínimo: " + min.orElseThrow()

            )

        );

        

        System.out.println(result);

    }

}

Y la salida sería: 

Promedio: 5.833333333333333, Mínimo: 2


El colector teeing en Java 12 proporciona una forma eficiente de combinar dos colectores en una sola operación de Stream, evitando iteraciones adicionales y haciendo el código más legible. Su versatilidad lo convierte en una herramienta valiosa para el procesamiento de datos en Java moderno.

miércoles, 29 de enero de 2025

Expresiones Switch en Java


Con Java 12, Oracle introdujo una nueva funcionalidad en el lenguaje: las expresiones switch, como parte de una característica en fase de vista previa. Esta adición busca mejorar la legibilidad y reducir la verbosidad del código al trabajar con estructuras switch.

En versiones anteriores de Java, la estructura switch era exclusivamente una sentencia, lo que significa que no devolvía un valor. Con la introducción de las expresiones switch, ahora puedes usar switch como una expresión que devuelve un valor, simplificando significativamente códigos comunes y eliminando la necesidad de manejar variables auxiliares.


Vea,mos un ejemplo básico de expresión switch


En versiones anteriores de Java:


int day = 3;

String dayName;

switch (day) {

    case 1:

        dayName = "Lunes";

        break;

    case 2:

        dayName = "Martes";

        break;

    case 3:

        dayName = "Miércoles";

        break;

    default:

        dayName = "Día inválido";

        break;

}

System.out.println(dayName);


Con expresiones switch en Java 12:


int day = 3;

String dayName = switch (day) {

    case 1 -> "Lunes";

    case 2 -> "Martes";

    case 3 -> "Miércoles";

    default -> "Día inválido";

};

System.out.println(dayName);


La nueva sintaxis también admite bloques de código más complejos, usando llaves, veamos un ejemplo:


int number = 5;

String parity = switch (number % 2) {

    case 0 -> {

        System.out.println("Es un número par.");

        yield "Par";

    }

    case 1 -> {

        System.out.println("Es un número impar.");

        yield "Impar";

    }

    default -> throw new IllegalStateException("Valor inesperado: " + number % 2);

};

System.out.println("El número es " + parity);


Las expresiones switch introducidas en Java 12 y estabilizada en Java 14, representan un paso importante hacia la modernización del lenguaje, ofreciendo una sintaxis más concisa y fácil de usar. Si bien inicialmente estaban en fase de vista previa, su adopción completa en versiones posteriores las convierte en una herramienta esencial para los desarrolladores Java modernos.


lunes, 27 de enero de 2025

Las características introducidas en las versiones de Java desde la 12 hasta la más reciente


Hace mucho que no pispeo las nuevas características de java, desde la 11 más o menos. Por lo tanto he resuelto hacer un post por cada nueva característica.

Java 12 (marzo 2019):

  •  Expresiones `switch` (vista previa): Permiten utilizar `switch` como una expresión, simplificando la sintaxis y reduciendo errores.
  •  API de Compilación de Resúmenes de Archivos: Facilita la generación de resúmenes hash para archivos y directorios.
  •  Colectores de Teeing: Introducción de un nuevo colector en la API de Streams que permite combinar dos colecciones en una.


Java 13 (septiembre 2019):

  •  Bloques de texto (vista previa): Permiten manejar cadenas de texto multilínea de manera más sencilla y legible.
  •  Mejoras en ZGC: El Garbage Collector Z se ha mejorado para devolver memoria al sistema operativo más eficientemente.


Java 14 (marzo 2020):

  •  Clases de registros (vista previa): Introducción de `record` para simplificar la creación de clases que son principalmente contenedores de datos.
  •  Coincidencia de patrones para `instanceof` (vista previa): Simplifica el uso de `instanceof` al permitir la asignación directa de la variable si la comprobación es exitosa.


Java 15 (septiembre 2020):

  •  Clases selladas (vista previa): Permiten restringir qué clases pueden heredar de una clase o implementar una interfaz, mejorando el control sobre la jerarquía de clases.
  •  Eliminación de Nashorn: El motor JavaScript Nashorn fue eliminado del JDK.


Java 16 (marzo 2021):

  •  Clases de registros: La funcionalidad de `record` se estabilizó, facilitando la creación de clases inmutables.
  •  API de Acceso a Memoria Externa (incubadora): Proporciona una forma segura y eficiente de acceder a memoria fuera del montón de Java.


Java 17 (septiembre 2021):

  •  Coincidencia de patrones para `switch` (vista previa): Extiende la coincidencia de patrones al `switch`, permitiendo casos basados en el tipo del argumento.
  •  Funciones de clase sellada: Las clases selladas se estabilizaron, ofreciendo un control más preciso sobre la herencia.


Java 18 (marzo 2022):

  •  API de Servidor Web Simple: Introduce una API para crear servidores web mínimos, útiles para pruebas y propósitos educativos.
  •  Mejoras en la API de Caracteres Unicode: Actualizaciones para soportar las últimas versiones del estándar Unicode.


Java 19 (septiembre 2022):

  •  API de Vectores (incubadora): Proporciona una API para operaciones vectoriales que pueden ser optimizadas en hardware compatible.
  •  Patrones de registros (vista previa): Extiende la coincidencia de patrones para trabajar con componentes de registros.


Java 20 (marzo 2023):

  •  Extensiones de la API de Memoria y Función Externa (vista previa): Mejoras en la API para interactuar con memoria y funciones externas de manera más segura y eficiente.
  •  Mejoras en la API de Vectores: Continúan las mejoras en la API de Vectores para un mejor rendimiento y soporte de hardware.


Java 21 (septiembre 2023):

  •  Clases sin nombre y métodos principales sin nombre (vista previa): Simplifica la creación de programas pequeños al eliminar la necesidad de clases y métodos principales explícitos.
  •  Mejoras en la coincidencia de patrones: Ampliaciones adicionales para la coincidencia de patrones en diversas estructuras del lenguaje.


Este es el resumen. Vamos a ver como me va. Si quieren que haga un post para otra característica, escriban en los comentarios. 



viernes, 10 de enero de 2025

Programación Reactiva con Spring WebFlux y Cassandra


Vamos a crear un proyecto webflux utilizando Cassndra. 

Primero creamos un proyecto Spring Boot y agregamos las dependencias necesarias:

  • spring-boot-starter-webflux
  • spring-boot-starter-data-cassandra-reactive


Si utilizamos maven el archivo pom.xml tendria estas dependencias :


<dependencies>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-webflux</artifactId>

    </dependency>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-cassandra-reactive</artifactId>

    </dependency>

    <dependency>

        <groupId>com.datastax.oss</groupId>

        <artifactId>java-driver-core</artifactId>

    </dependency>

</dependencies>

Si usamos gradle seria algo así : 

        implementation("org.springframework.boot:spring-boot-starter-data-cassandra-reactive")

implementation("org.springframework.boot:spring-boot-starter-webflux")


Agregamos la configuración de Cassandra en application.yml:


spring:

  data:

    cassandra:

      contact-points: [localhost]

      port: 9042

      keyspace-name: demo_keyspace

      schema-action: create-if-not-exists

o en el properties: 

spring.cassandra.contact-points=127.0.0.1

spring.cassandra.port=9042

spring.cassandra.keyspace-name=demo_keyspace

spring.cassandra.schema-action= create-if-not-exists

spring.cassandra.local-datacenter=datacenter1


Ahora vamos a definir una entidad para guardar y recuperar:


import org.springframework.data.annotation.Id;

import org.springframework.data.cassandra.core.mapping.PrimaryKey;

import org.springframework.data.cassandra.core.mapping.Table;


@Table("products")

public class Product {

    @Id

    @PrimaryKey

    private String id;

    private String name;

    private double price;


    // Getters y setters

}


Crea un repositorio usando ReactiveCassandraRepository:


import org.springframework.data.cassandra.repository.ReactiveCassandraRepository;

import org.springframework.stereotype.Repository;


@Repository

public interface ProductRepository extends ReactiveCassandraRepository<Product, String> {

}


Ahora hacemos el servicio: 


import org.springframework.stereotype.Service;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;


@Service

public class ProductService {


    private final ProductRepository productRepository;


    public ProductService(ProductRepository productRepository) {

        this.productRepository = productRepository;

    }


    public Flux<Product> getAllProducts() {

        return productRepository.findAll();

    }


    public Mono<Product> getProductById(String id) {

        return productRepository.findById(id);

    }


    public Mono<Product> createProduct(Product product) {

        return productRepository.save(product);

    }


    public Mono<Void> deleteProduct(String id) {

        return productRepository.deleteById(id);

    }

}


Ahora creamos un controlador REST con WebFlux:


import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;


@RestController

@RequestMapping("/products")

public class ProductController {


    private final ProductService productService;


    public ProductController(ProductService productService) {

        this.productService = productService;

    }


    @GetMapping

    public Flux<Product> getAllProducts() {

        return productService.getAllProducts();

    }


    @GetMapping("/{id}")

    public Mono<Product> getProductById(@PathVariable String id) {

        return productService.getProductById(id);

    }


    @PostMapping

    public Mono<Product> createProduct(@RequestBody Product product) {

        return productService.createProduct(product);

    }


    @DeleteMapping("/{id}")

    public Mono<Void> deleteProduct(@PathVariable String id) {

        return productService.deleteProduct(id);

    }

}


Por ultimo tenemos que agregar las anotaciones @EnableReactiveCassandraRepositories y @Push a nuestro application : 


@SpringBootApplication

@EnableReactiveCassandraRepositories

@Push

class ApplicationDemo : AppShellConfigurator


fun main(args: Array<String>) {

runApplication<ApplicationDemo>(*args)

}


Y ahora podemos probar nuestros servicios. 

jueves, 2 de enero de 2025

Cómo Utilizar ANTLR en Java?


ANTLR (Another Tool for Language Recognition) es una herramienta potente para generar analizadores léxicos y sintácticos.

Vamos a ver como podemos usarla en java

Creamos el archivo `build.gradle


   plugins {

       id 'java'

       id 'antlr' version '1.0.1'

   }


   repositories {

       mavenCentral()

   }


   dependencies {

       implementation 'org.antlr:antlr4-runtime:4.9.3'

       antlr 'org.antlr:antlr4:4.9.3'

   }


   sourceSets {

       main {

           java {

               srcDirs = ['build/generated-src/antlr/main']

           }

       }

   }


   antlr {

       arguments += ['-no-listener', '-visitor']

   }


Creamos el archivo de gramática .g4 de ANTLR en src/main/antlr4. Por ejemplo, Hello.g4:


   grammar Hello;


   r  : 'hello' ID ;

   ID : [a-zA-Z]+ ;

   WS : [ \t\r\n]+ -> skip ;


Construimos el Proyecto para esto ejecutamos el siguiente comando para construir el proyecto y generamos los archivos necesarios:


   gradle build


Ejecutamos el proyecto, asegúranodonos que el archivo Main.java esté en `src/main/java`:


   import org.antlr.v4.runtime.CharStreams;

   import org.antlr.v4.runtime.CommonTokenStream;


   public class Main {

       public static void main(String[] args) {

           String input = "hello world";

           HelloLexer lexer = new HelloLexer(CharStreams.fromString(input));

           CommonTokenStream tokens = new CommonTokenStream(lexer);

           HelloParser parser = new HelloParser(tokens);

           parser.r();  // Inicia el análisis sintáctico a partir de la regla 'r'

       }

   }



Ejecutamos la aplicación con:


   gradle run


Hemos explorado cómo configurar y utilizar ANTLR en un proyecto Java usando Gradle. Aprendimos a definir una gramática, generar el lexer y el parser, y utilizamos estos componentes en una aplicación Java. ANTLR es una herramienta flexible que te permite construir analizadores personalizados para tus necesidades.

viernes, 20 de diciembre de 2024

Dropwizard: Servicios RESTful en Java


Dropwizard es un framework para construir servicios web RESTful en Java de forma rápida y eficiente. Este marco combina varias bibliotecas maduras como Jetty, Jersey, Jackson y Metrics en un único paquete cohesivo, eliminando la complejidad de configuraciones manuales.

¿Por qué usar Dropwizard?

  1. Configuración Simplificada: Usa una estructura de proyecto preconfigurada.
  2. Eficiencia: Basado en Jetty, ofrece un servidor web de alto rendimiento.
  3. Monitorización: Incluye herramientas para métricas y monitoreo listas para usar.
  4. Integración: Compatible con Jersey para manejar endpoints RESTful y Jackson para JSON.
  5. Producción-Ready: Diseñado para entornos de producción con soporte para configuración YAML y validaciones.

Para comenzar, necesitas agregar Dropwizard a tu proyecto Maven:


<dependency>

    <groupId>io.dropwizard</groupId>

    <artifactId>dropwizard-core</artifactId>

    <version>2.1.4</version>

</dependency>


Un proyecto típico de Dropwizard tiene tres componentes principales:

  • Aplicación (`MyApplication`): Configura el servicio y los recursos.
  • Configuración (`MyConfiguration`): Define las opciones de configuración en YAML.
  • Recursos (`MyResource`): Implementa los endpoints RESTful.


Veamos un ejemplo, primero empezamos configurando: 


import io.dropwizard.Application;

import io.dropwizard.setup.Bootstrap;

import io.dropwizard.setup.Environment;


public class HelloWorldApplication extends Application<HelloWorldConfiguration> {


    public static void main(String[] args) throws Exception {

        new HelloWorldApplication().run(args);

    }


    @Override

    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {

        // Inicialización si es necesaria

    }


    @Override

    public void run(HelloWorldConfiguration configuration, Environment environment) {

        final HelloWorldResource resource = new HelloWorldResource(configuration.getDefaultName());

        environment.jersey().register(resource);

    }

}


Crea un archivo config.yml:


defaultName: "Mundo"

server:

  applicationConnectors:

    - type: http

      port: 8080

  adminConnectors:

    - type: http

      port: 8081


Por ultimo hacemos nuestros servicios: 


import javax.ws.rs.GET;

import javax.ws.rs.Path;

import javax.ws.rs.Produces;

import javax.ws.rs.core.MediaType;


@Path("/hello")

@Produces(MediaType.APPLICATION_JSON)

public class HelloWorldResource {


    private final String defaultName;


    public HelloWorldResource(String defaultName) {

        this.defaultName = defaultName;

    }


    @GET

    public String sayHello() {

        return String.format("Hola, %s!", defaultName);

    }

}


Y la configuración va ser: 


import io.dropwizard.Configuration;

import com.fasterxml.jackson.annotation.JsonProperty;

import javax.validation.constraints.NotEmpty;


public class HelloWorldConfiguration extends Configuration {


    @NotEmpty

    private String defaultName;


    @JsonProperty

    public String getDefaultName() {

        return defaultName;

    }


    @JsonProperty

    public void setDefaultName(String defaultName) {

        this.defaultName = defaultName;

    }

}


Y luego levantamos el server y vamos a http://localhost:8080/hello donde veremos nuestro "hello!" 


Dropwizard es una opción excelente para construir servicios RESTful en Java con un enfoque minimalista. La verdad no me queda claro porque eligiría dropwizard y no spring boot. Si alguien sabe escriba en los comentarios. 


Dejo link: https://www.dropwizard.io/en/stable/

sábado, 14 de diciembre de 2024

LangChain4j: IA Generativa en Java


LangChain4j es un poderoso framework para construir aplicaciones de inteligencia artificial generativa en Java. Inspirado en el popular LangChain para Python y JavaScript, este marco permite integrar modelos de lenguaje como OpenAI GPT, Llama, o Hugging Face con herramientas avanzadas, flujos de trabajo y procesamiento dinámico.

LangChain4j proporciona herramientas para manejar modelos de lenguaje de manera modular y escalable. Algunas de sus características destacadas incluyen:

  • Integración de Modelos de Lenguaje (LLMs): Interactúa fácilmente con GPT-4, GPT-3, o modelos personalizados.
  • Encadenamiento de Operaciones: Diseña flujos complejos combinando varios modelos y herramientas.
  • Contexto Extendido: Utiliza almacenamiento vectorial para manejar contextos largos.
  • Herramientas de Razonamiento y Extracción: Construye aplicaciones como chatbots avanzados, asistentes de búsqueda, o sistemas de recomendación.

Antes de comenzar, agrega la dependencia en tu proyecto Maven o Gradle:


Veamos la dependencia de maven:

<dependency>

    <groupId>com.langchain4j</groupId>

    <artifactId>langchain4j-core</artifactId>

    <version>1.0.0</version>

</dependency>


o gradle:


implementation 'com.langchain4j:langchain4j-core:1.0.0'


Veamos un cliente básico para interactuar con OpenAI GPT:


import com.langchain4j.LangChain;

import com.langchain4j.llm.OpenAiClient;


public class LangChainExample {

    public static void main(String[] args) {

        OpenAiClient client = OpenAiClient.builder()

                .apiKey("tu-api-key")

                .build();


        String response = client.chat("¿Qué es LangChain4j?");

        System.out.println("Respuesta: " + response);

    }

}


Este ejemplo muestra cómo enviar una consulta y recibir una respuesta usando OpenAI GPT.

LangChain4j soporta herramientas como cadenas de procesamiento (`Chains`) para flujos más complejos.


Veamos un ejemplo de un Flujo con Memoria:


import com.langchain4j.chain.ConversationChain;

import com.langchain4j.memory.InMemoryMemory;


public class ConversationExample {

    public static void main(String[] args) {

        ConversationChain conversation = ConversationChain.builder()

                .llm(OpenAiClient.builder().apiKey("tu-api-key").build())

                .memory(new InMemoryMemory())

                .build();


        System.out.println(conversation.chat("Hola, ¿quién eres?"));

        System.out.println(conversation.chat("¿Recuerdas mi nombre?"));

    }

}


Aquí, InMemoryMemory permite que el modelo recuerde las interacciones previas.


LangChain4j admite almacenamiento vectorial, útil para aplicaciones de búsqueda semántica o contextos largos.


import com.langchain4j.vector.PineconeVectorStore;


public class VectorStoreExample {

    public static void main(String[] args) {

        PineconeVectorStore vectorStore = PineconeVectorStore.builder()

                .apiKey("tu-api-key")

                .environment("us-west1-gcp")

                .build();


        vectorStore.add("doc1", "Este es un ejemplo de texto.");

        System.out.println(vectorStore.search("texto relacionado", 1));

    }

}


LangChain4j extiende las capacidades de los modelos de lenguaje para aplicaciones empresariales en Java. Con su enfoque modular, herramientas avanzadas, y soporte para almacenamiento vectorial, se posiciona como una opción clave para proyectos de IA generativa en el ecosistema Java.

Y falto decir que se puede integrar con spring y otros frameworks, pero eso lo voy a dejar para otro post... 

Dejo link: https://docs.langchain4j.dev/


sábado, 9 de noviembre de 2024

GraalVM + sistema operativo = GraalOS


GraalOS es una iniciativa experimental que integra la tecnología de GraalVM directamente en el sistema operativo, permitiendo que las aplicaciones, especialmente las desarrolladas en lenguajes JVM (Java, Scala, Kotlin), se ejecuten de manera más eficiente y directa sobre el hardware. GraalOS busca ser un sistema operativo minimalista y optimizado para ejecutar aplicaciones de alto rendimiento, proporcionando un entorno ideal para microservicios, procesamiento en la nube y aplicaciones en tiempo real.

Las principales características de GraalOS son: 

  1. Soporte Nativo para Lenguajes JVM: GraalOS permite ejecutar código de JVM directamente sobre el sistema operativo sin capas intermedias, ofreciendo un rendimiento nativo para lenguajes como Java, Kotlin y Scala.
  2. Integración con GraalVM: GraalOS está construido sobre la base de GraalVM, lo que permite la compilación AOT (Ahead-of-Time) y el uso de `native-image` para generar binarios nativos que corren eficientemente sobre el hardware.
  3. Ecosistema Multilenguaje: Aunque está optimizado para lenguajes de la JVM, GraalOS también soporta otros lenguajes como JavaScript, Python y R, aprovechando la compatibilidad de GraalVM.
  4. Optimización para Microservicios: GraalOS está diseñado para ejecutarse en contenedores ligeros, ideales para arquitecturas de microservicios y entornos de computación en la nube.

Uno de los puntos fuertes de GraalOS es el uso de la tecnología de compilación Ahead-of-Time (AOT) de GraalVM. La compilación AOT permite que el código de JVM se convierta en código nativo, lo cual mejora significativamente el tiempo de inicio y reduce el uso de memoria.

native-image -jar tu_aplicacion.jar

Este comando convierte un archivo JAR en un binario nativo, optimizado y listo para ejecutarse en GraalOS. Los binarios nativos generados pueden arrancar casi instantáneamente y son ideales para aplicaciones que requieren respuesta en tiempo real.

GraalOS ofrece un entorno perfecto para el despliegue de aplicaciones en la nube gracias a su integración optimizada con GraalVM. Además, permite manejar aplicaciones en tiempo real gracias a su bajo tiempo de respuesta y consumo de recursos. Su diseño minimalista y eficiente hace que sea una opción atractiva para desarrolladores que busquen optimizar costos y rendimiento en entornos de microservicios o serverless.

Aunque GraalOS es experimental, se puede probar en entornos de contenedores o como un sistema operativo en máquinas virtuales para evaluar su rendimiento en aplicaciones específicas. Para comenzar, puedes instalar GraalOS en una máquina virtual y luego utilizar GraalVM para compilar y ejecutar aplicaciones.


apt update && apt install graalos


GraalOS representa un avance en la forma en que interactuamos con el hardware a nivel de sistema operativo para ejecutar aplicaciones nativas. Aunque en sus primeras etapas, su integración con GraalVM abre la puerta a nuevas oportunidades en la ejecución de aplicaciones de alto rendimiento y microservicios en la nube.

Con una promesa de rendimiento optimizado, tiempos de respuesta ultrarrápidos y soporte multilenguaje, GraalOS podría transformar la forma en que desarrollamos e implementamos aplicaciones nativas.

Dejo like : 

https://blogs.oracle.com/java/post/introducing-graalos

https://graal.cloud/

jueves, 31 de octubre de 2024

Le pregunte a la IA : ¿Qué lenguaje tiene las mejores perspectivas de futuro: Python, Java o JavaScript?

Le pregunte a la IA : ¿Qué lenguaje tiene las mejores perspectivas de futuro: Python, Java o JavaScript? y como me gusto mucho su respuesta se las comparto: 

Para evaluar el futuro de Python, Java, y JavaScript, consideremos cómo se están usando, su versatilidad y las tendencias que los impulsan en áreas clave:


Python

   - Ventajas: Python es ampliamente valorado por su legibilidad y simplicidad, lo cual lo hace popular tanto entre principiantes como en sectores avanzados como la ciencia de datos, la inteligencia artificial (IA), y el análisis de datos. Su ecosistema ofrece un gran soporte en estas áreas, con bibliotecas como TensorFlow, Pandas, y NumPy.

   - Perspectivas de Futuro: Su relevancia en IA y ciencia de datos seguirá creciendo, dado que es el lenguaje de referencia en estos campos. Aunque tiene limitaciones de rendimiento comparado con lenguajes de bajo nivel, las mejoras continuas en sus bibliotecas y en plataformas de soporte (como el uso de PyPy y la integración con código en C++) pueden mitigar estas limitaciones. Sin embargo, en áreas que demandan alto rendimiento en tiempo real, como juegos y aplicaciones de alta concurrencia, su uso podría ser limitado.


Java

   - Ventajas: Java es conocido por su estabilidad y robustez, especialmente en entornos empresariales y sistemas a gran escala. La JVM (Java Virtual Machine) permite que las aplicaciones en Java se ejecuten de manera confiable en múltiples plataformas. Java también es ampliamente utilizado en aplicaciones de Android y sigue siendo un estándar en muchas empresas.

   - Perspectivas de Futuro: La madurez y confiabilidad de Java aseguran su presencia en grandes empresas y aplicaciones financieras, que demandan sistemas sólidos y escalables. Recientemente, con mejoras de rendimiento en las versiones más nuevas y características de programación moderna (como pattern matching y records), Java sigue evolucionando y atrayendo a una nueva generación de desarrolladores. Su uso en aplicaciones web modernas y su compatibilidad con entornos de nube son elementos clave que aseguran su vigencia en el mercado.


JavaScript

   - Ventajas: JavaScript es el lenguaje dominante en el desarrollo web, y su versatilidad ha crecido enormemente con el ecosistema Node.js, lo cual permite su uso tanto en el frontend como en el backend. Su capacidad para construir aplicaciones de una sola página (SPA), junto con frameworks como React, Vue, y Angular, le ha dado un rol esencial en la web moderna.

   - Perspectivas de Futuro: La demanda de aplicaciones web interactivas y rápidas respalda el crecimiento de JavaScript. Además, su capacidad de integrarse con **WebAssembly (Wasm)** ha ampliado su uso en aplicaciones de alto rendimiento en el navegador. Node.js sigue siendo relevante para el backend, y con la evolución continua del lenguaje (por ejemplo, ES2022), JavaScript se mantiene competitivo. 


- Python: dominará en ciencia de datos, IA y aplicaciones académicas; su simplicidad asegura su uso entre nuevos programadores.

- Java: mantiene su posición en el desarrollo empresarial y de sistemas complejos; su futuro está asegurado en estos sectores.

- JavaScript: seguirá siendo fundamental en el desarrollo web, y su interoperabilidad con WebAssembly amplía sus horizontes.


En general, la elección del lenguaje con las "mejores perspectivas" depende del campo específico. Para IA y datos, Python; para sistemas empresariales, Java; y para la web y aplicaciones de usuario, JavaScript. Cada uno tiene un rol fuerte y perspectivas sólidas en sus respectivos dominios.


Que piensan? 

miércoles, 25 de septiembre de 2024

Apache Geode: Almacenamiento de Datos Distribuido en Tiempo Real


En el mundo actual, donde las aplicaciones demandan respuestas inmediatas y alta disponibilidad de datos, es crucial contar con herramientas que permitan gestionar datos en tiempo real de manera distribuida. Apache Geode es una de esas soluciones que permiten construir aplicaciones escalables y altamente disponibles.

Apache Geode es un sistema de almacenamiento de datos en memoria distribuido que ofrece capacidades de procesamiento y almacenamiento en tiempo real. Originalmente desarrollado por GemStone bajo el nombre de GemFire, pasó a ser un proyecto de código abierto bajo el paraguas de la Apache Software Foundation. 

Apache Geode se caracteriza por su capacidad para almacenar datos en memoria distribuidos entre varios nodos, permitiendo así un acceso rápido y eficiente a grandes volúmenes de datos. Ofrece baja latencia, alta disponibilidad, y consistencia, lo que lo convierte en una opción ideal para aplicaciones críticas que requieren acceso en tiempo real a los datos.

Apache Geode distribuye los datos entre múltiples nodos (o servidores), formando un clúster donde cada nodo puede almacenar una parte de los datos. De esta forma, el sistema es capaz de escalar horizontalmente a medida que aumenta la demanda. Además, Geode puede replicar los datos entre los nodos para garantizar redundancia y alta disponibilidad.

La arquitectura de Apache Geode permite particionar y replicar datos de manera eficiente. Esto significa que cada partición de datos se almacena en un nodo del clúster, y estas particiones pueden replicarse en otros nodos para evitar pérdida de información en caso de fallos.

Además, Geode ofrece consistencia fuerte, lo que significa que los datos son siempre consistentes entre las réplicas, lo cual es fundamental en entornos de alta disponibilidad.

Características Principales de Apache Geode:

  1. Almacenamiento en Memoria: Apache Geode utiliza la memoria principal de los servidores para almacenar los datos, lo que reduce drásticamente la latencia de acceso en comparación con bases de datos tradicionales basadas en disco.
  2. Distribución y Replicación de Datos: Los datos en Geode se distribuyen entre varios nodos y pueden replicarse para garantizar redundancia y alta disponibilidad.
  3. Alta Disponibilidad y Tolerancia a Fallos: Al replicar los datos en diferentes nodos del clúster, Geode garantiza que los datos estarán disponibles incluso si uno o varios nodos fallan.
  4. Consistencia: Apache Geode asegura consistencia fuerte, es decir, cualquier cambio en los datos es inmediatamente visible en todos los nodos que almacenan copias del mismo dato.
  5. Procesamiento en Tiempo Real: Permite realizar consultas y operaciones sobre los datos en tiempo real, manteniendo la latencia baja incluso en sistemas con altos volúmenes de transacciones.
  6. Soporte para APIs de Java y Spring: Geode está profundamente integrado con Java y tiene un fuerte soporte para el ecosistema Spring, lo que facilita su integración en aplicaciones Java empresariales.
  7. Persistencia: Aunque su principal almacenamiento es en memoria, Geode permite configurar persistencia en disco para asegurar que los datos no se pierdan tras un reinicio o fallo catastrófico.

Y donde podemos utilizar Geode: 

  1. Aplicaciones Financieras: En sistemas de trading y banca, donde la baja latencia y la consistencia de datos son cruciales, Geode se utiliza para garantizar acceso rápido a los datos en tiempo real.
  2. eCommerce: Plataformas de comercio electrónico, donde es necesario manejar grandes cantidades de usuarios concurrentes y transacciones, pueden beneficiarse de la capacidad de escalado y alta disponibilidad de Geode.
  3. Sistemas de Telecomunicaciones: Las redes de telecomunicaciones requieren acceso constante a la información del usuario y deben procesar grandes volúmenes de datos en tiempo real, algo que Apache Geode maneja eficientemente.
  4. Monitorización en Tiempo Real: Para sistemas de monitoreo y análisis en tiempo real, Geode permite el procesamiento y la toma de decisiones rápidas basadas en datos en memoria, sin la necesidad de acceder a discos lentos.

Cuando comparamos a Apache Geode con otras soluciones de almacenamiento en memoria como Redis o Hazelcast, la diferencia radica en el soporte más amplio de Apache Geode para modelos de datos más complejos y la integración nativa con Spring, lo que facilita su adopción en entornos Java empresariales.

Por otro lado, en comparación con bases de datos tradicionales como MySQL o PostgreSQL, Geode ofrece una arquitectura distribuida en memoria, lo que reduce significativamente la latencia de acceso y permite una mayor escalabilidad.

Apache Geode es una herramienta poderosa para desarrollar aplicaciones críticas que requieren almacenamiento distribuido en memoria y acceso en tiempo real a los datos. Su integración con tecnologías como Java y Spring, junto con su capacidad de escalabilidad y alta disponibilidad, lo convierten en una opción excelente para sectores como finanzas, telecomunicaciones, y comercio electrónico.

Dejo link; https://geode.apache.org/

viernes, 20 de septiembre de 2024

Programación Reactiva con Spring


La programación reactiva es un paradigma orientado a manejar flujos de datos de manera asíncrona, lo cual resulta ideal para aplicaciones con alta carga de tráfico, como sistemas de microservicios. Con Spring, la programación reactiva se facilita mediante el módulo Spring WebFlux.

Spring WebFlux es el módulo reactivo de Spring que permite construir aplicaciones no bloqueantes y asíncronas. Está basado en el patrón Reactor, que sigue el estándar de Reactive Streams y utiliza Mono y Flux como las abstracciones principales para manejar uno o varios elementos, respectivamente.

  • Mono: Representa 0 o 1 elemento.
  • Flux: Representa 0 o N elementos.
  • Backpressure: Mecanismo para controlar la velocidad de emisión de los eventos.

Primero, crea un proyecto de Spring Boot en Spring Initializr. Asegúrate de agregar las dependencias de Spring Reactive Web.


<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-webflux</artifactId>

</dependency>


A continuación, implementamos un controlador que responde a peticiones HTTP de manera reactiva usando `Flux` y `Mono`.


import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;


import java.time.Duration;


@RestController

public class ReactiveController {


    // Endpoint que devuelve un solo valor (Mono)

    @GetMapping("/mono/{id}")

    public Mono<String> getMono(@PathVariable String id) {

        return Mono.just("Valor recibido: " + id);

    }


    // Endpoint que devuelve un flujo continuo de datos (Flux)

    @GetMapping("/flux")

    public Flux<Integer> getFlux() {

        return Flux.range(1, 10)

                   .delayElements(Duration.ofSeconds(1));

    }

}


Una vez que hayas implementado el controlador, ejecuta la aplicación de Spring Boot. Puedes acceder a los endpoints:

  • /mono/{id}: Devuelve un único valor. Ejemplo: http://localhost:8080/mono/5
  • /flux: Devuelve un flujo de datos continuo que se emite cada segundo. Ejemplo: http://localhost:8080/flux
Como ventajas podemos ver: 
  • Eficiencia y Escalabilidad: Ideal para manejar aplicaciones que requieren alta concurrencia y asíncronas.
  • Control del Flujo: Con Reactive Streams puedes controlar el ritmo de procesamiento y evitar la sobrecarga del sistema.
  • Menos Bloqueo: No hay hilos bloqueados mientras se esperan respuestas, lo que mejora el rendimiento en sistemas de alta demanda.


viernes, 23 de agosto de 2024

lunes, 19 de agosto de 2024

Se encuentran abiertas las inscripciones para los cursos Gugler!!!

¡Tengo grandes noticias! Estoy emocionado de anunciar que ya están abiertas las inscripciones para los tan esperados cursos Gugler. Si estás buscando avanzar en tu carrera, aprender nuevas habilidades, o simplemente profundizar tus conocimientos en áreas tecnológicas, ¡estos cursos son para ti!







Inscripciones abiertas del segundo cuatrimestre 2024. Inscripciones.gugler.com.ar

lunes, 12 de agosto de 2024

Procedimientos Almacenados y Funciones en H2


H2 es una base de datos relacional escrita en Java que es especialmente popular por su ligereza y facilidad de uso. Aunque es muy común utilizar H2 como una base de datos en memoria para pruebas, también es lo suficientemente potente para manejar operaciones más avanzadas, como procedimientos almacenados y funciones. 

Un procedimiento almacenado es un conjunto de instrucciones SQL que pueden ser almacenadas en la base de datos y ejecutadas cuando sea necesario. Los procedimientos almacenados son útiles porque permiten encapsular lógica compleja en un solo lugar, lo que facilita su mantenimiento y reutilización.

Las funciones son similares a los procedimientos almacenados, pero con algunas diferencias clave. Mientras que un procedimiento almacenado puede ejecutar una serie de comandos SQL y no necesariamente retornar un valor, una función siempre retorna un valor y está diseñada para ser utilizada en expresiones SQL.

En H2, los procedimientos almacenados se crean utilizando la palabra clave `CREATE ALIAS`. Veamos un ejemplo sencillo de cómo crear un procedimiento almacenado que inserta un nuevo registro en una tabla:


CREATE ALIAS insert_user AS $$

void insert_user(Connection conn, String username, String email) throws SQLException {

    PreparedStatement prep = conn.prepareStatement("INSERT INTO users(username, email) VALUES(?, ?)");

    prep.setString(1, username);

    prep.setString(2, email);

    prep.execute();

    prep.close();

}

$$;


Una vez que el procedimiento almacenado ha sido creado, puedes llamarlo usando `CALL`:


CALL insert_user('JohnDoe', 'john.doe@example.com');


Si necesitas que tu procedimiento devuelva resultados, puedes modificarlo ligeramente:


CREATE ALIAS get_user_by_id AS $$

ResultSet get_user_by_id(Connection conn, int id) throws SQLException {

    PreparedStatement prep = conn.prepareStatement("SELECT * FROM users WHERE id = ?");

    prep.setInt(1, id);

    return prep.executeQuery();

}

$$;


Luego puedes utilizar el procedimiento en una consulta:


CALL get_user_by_id(1);


Al igual que los procedimientos, las funciones en H2 se crean utilizando `CREATE ALIAS`, pero la diferencia es que las funciones siempre retornan un valor. Aquí tienes un ejemplo de una función que calcula el IVA de un precio dado:


CREATE ALIAS calculate_vat AS $$

double calculate_vat(double price) {

    return price * 0.21;

}

$$;


Una vez creada, puedes utilizar la función en tus consultas SQL:


SELECT calculate_vat(100) AS vat_amount;


Esto te devolverá el valor con el IVA aplicado.


H2 ofrece un soporte robusto para procedimientos almacenados y funciones, lo que lo hace muy útil incluso en aplicaciones más allá del simple almacenamiento de datos en memoria. Con la capacidad de encapsular lógica SQL compleja en procedimientos y funciones, puedes mantener tu código más limpio y organizado.