Java
Java es un lenguaje de programación de alto nivel, orientado a objetos, que fue desarrollado por Sun Microsystems (ahora propiedad de Oracle) y lanzado en 1995. Es conocido por su portabilidad ("write once, run anywhere" o "escribe una vez, ejecuta en cualquier lugar"), robustez y amplia adopción en diversos sectores de la industria del software.
Características Principales
1. Orientación a Objetos
Java es un lenguaje fuertemente orientado a objetos, donde casi todo es un objeto. Esto promueve:
- Encapsulamiento: Ocultación de detalles de implementación
- Herencia: Reutilización de código a través de jerarquías de clases
- Polimorfismo: Capacidad de los objetos para tomar diferentes formas
- Abstracción: Representación de conceptos complejos de forma simplificada
2. Independencia de Plataforma
El código Java se compila a bytecode, que es ejecutado por la Máquina Virtual de Java (JVM). Esto permite que los programas Java se ejecuten en cualquier dispositivo que tenga una JVM, independientemente del sistema operativo subyacente.
3. Gestión Automática de Memoria
Java utiliza un recolector de basura (garbage collector) que gestiona automáticamente la asignación y liberación de memoria, reduciendo la probabilidad de fugas de memoria y errores de puntero nulo.
4. Tipado Fuerte y Estático
Java es un lenguaje de tipado fuerte, lo que significa que el tipo de una variable se verifica en tiempo de compilación, reduciendo errores en tiempo de ejecución.
5. Multithreading
Java ofrece soporte nativo para la programación concurrente a través de hilos (threads), permitiendo que múltiples tareas se ejecuten simultáneamente.
Sintaxis Básica
Estructura de un Programa Java
// Declaración del paquete
package com.example;
// Importaciones
import java.util.List;
import java.util.ArrayList;
// Declaración de la clase
public class EjemploJava {
// Variable de instancia
private String mensaje;
// Constructor
public EjemploJava(String mensaje) {
this.mensaje = mensaje;
}
// Método
public void mostrarMensaje() {
System.out.println(mensaje);
}
// Método principal (punto de entrada)
public static void main(String[] args) {
EjemploJava ejemplo = new EjemploJava("¡Hola, mundo!");
ejemplo.mostrarMensaje();
}
}
Tipos de Datos
Tipos Primitivos
- byte: 8 bits, valores de -128 a 127
- short: 16 bits, valores de -32,768 a 32,767
- int: 32 bits, valores de -2^31 a 2^31-1
- long: 64 bits, valores de -2^63 a 2^63-1
- float: 32 bits, punto flotante de precisión simple
- double: 64 bits, punto flotante de precisión doble
- char: 16 bits, un único carácter Unicode
- boolean: true o false
Tipos de Referencia
- Clases: String, ArrayList, HashMap, etc.
- Interfaces: List, Map, Set, etc.
- Arrays: int[], String[], Object[], etc.
Estructuras de Control
Condicionales
// If-else
if (condicion) {
// código si es verdadero
} else if (otraCondicion) {
// código si la primera condición es falsa y la segunda es verdadera
} else {
// código si ambas condiciones son falsas
}
// Switch
switch (variable) {
case valor1:
// código para valor1
break;
case valor2:
// código para valor2
break;
default:
// código por defecto
}
Bucles
// For
for (int i = 0; i < 10; i++) {
// código a repetir
}
// While
while (condicion) {
// código a repetir mientras la condición sea verdadera
}
// Do-While
do {
// código que se ejecuta al menos una vez
} while (condicion);
// For-each (enhanced for)
for (Tipo elemento : coleccion) {
// código para procesar cada elemento
}
Programación Orientada a Objetos en Java
Clases y Objetos
// Definición de una clase
public class Persona {
// Atributos (variables de instancia)
private String nombre;
private int edad;
// Constructor
public Persona(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
// Métodos
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public void presentar() {
System.out.println("Hola, mi nombre es " + nombre + " y tengo " + edad + " años.");
}
}
// Creación y uso de objetos
Persona persona1 = new Persona("Juan", 30);
persona1.presentar();
Herencia
// Clase base
public class Animal {
protected String nombre;
public Animal(String nombre) {
this.nombre = nombre;
}
public void emitirSonido() {
System.out.println("Sonido genérico de animal");
}
}
// Clase derivada
public class Perro extends Animal {
public Perro(String nombre) {
super(nombre);
}
@Override
public void emitirSonido() {
System.out.println("¡Guau guau!");
}
public void moverCola() {
System.out.println(nombre + " está moviendo la cola");
}
}
Interfaces
// Definición de una interfaz
public interface Volador {
void volar();
double getAltitudMaxima();
}
// Implementación de la interfaz
public class Pajaro implements Volador {
@Override
public void volar() {
System.out.println("El pájaro está volando");
}
@Override
public double getAltitudMaxima() {
return 1000.0;
}
}
Polimorfismo
// Uso de polimorfismo
Animal animal1 = new Perro("Rex");
Animal animal2 = new Gato("Felix");
animal1.emitirSonido(); // Salida: "¡Guau guau!"
animal2.emitirSonido(); // Salida: "¡Miau!"
// Lista polimórfica
List<Animal> animales = new ArrayList<>();
animales.add(new Perro("Rex"));
animales.add(new Gato("Felix"));
for (Animal animal : animales) {
animal.emitirSonido(); // Llama al método apropiado para cada tipo
}
Recursos Avanzados
Genéricos
// Definición de una clase genérica
public class Caja<T> {
private T contenido;
public void agregar(T contenido) {
this.contenido = contenido;
}
public T obtener() {
return contenido;
}
}
// Uso de genéricos
Caja<String> cajaDeTexto = new Caja<>();
cajaDeTexto.agregar("¡Hola, mundo!");
String texto = cajaDeTexto.obtener();
Caja<Integer> cajaDeNumero = new Caja<>();
cajaDeNumero.agregar(42);
int numero = cajaDeNumero.obtener();
Lambdas y Streams (Java 8+)
// Expresiones lambda
List<String> nombres = Arrays.asList("Ana", "Carlos", "Bruno", "Diana");
// Ordenamiento usando lambda
nombres.sort((s1, s2) -> s1.compareTo(s2));
// Filtro usando lambda
List<String> nombresConC = nombres.stream()
.filter(nombre -> nombre.startsWith("C"))
.collect(Collectors.toList());
// Transformación usando lambda
List<Integer> tamanos = nombres.stream()
.map(String::length)
.collect(Collectors.toList());
// Reducción usando lambda
int totalCaracteres = nombres.stream()
.mapToInt(String::length)
.sum();
Optional (Java 8+)
// Uso de Optional para evitar NullPointerException
public Optional<Usuario> buscarUsuarioPorId(Long id) {
// Búsqueda en la base de datos
Usuario usuario = repositorio.findById(id);
return Optional.ofNullable(usuario);
}
// Consumiendo un Optional
Optional<Usuario> resultado = buscarUsuarioPorId(123L);
resultado.ifPresent(usuario -> System.out.println("Usuario encontrado: " + usuario.getNombre()));
// Valor por defecto si no se encuentra
Usuario usuario = resultado.orElse(new Usuario("Usuario por Defecto"));
// Lanzar excepción si no se encuentra
Usuario usuarioEncontrado = resultado.orElseThrow(() -> new UsuarioNoEncontradoException("Usuario no encontrado"));
Anotaciones
// Definición de una anotación personalizada
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MiAnotacion {
String valor() default "";
int contador() default 0;
}
// Uso de anotaciones
public class EjemploAnotacion {
@MiAnotacion(valor = "prueba", contador = 5)
public void metodoAnotado() {
// Implementación
}
// Procesamiento de anotaciones en tiempo de ejecución
public static void main(String[] args) throws Exception {
Method metodo = EjemploAnotacion.class.getMethod("metodoAnotado");
if (metodo.isAnnotationPresent(MiAnotacion.class)) {
MiAnotacion anotacion = metodo.getAnnotation(MiAnotacion.class);
System.out.println("Valor: " + anotacion.valor());
System.out.println("Contador: " + anotacion.contador());
}
}
}
Ecosistema de Java
Herramientas de Construcción (Build)
- Maven: Gestión de dependencias y automatización de la construcción
- Gradle: Sistema de automatización de construcción flexible
Frameworks Populares
- Spring: Framework para el desarrollo de aplicaciones empresariales
- Hibernate: Framework ORM (Mapeo Objeto-Relacional)
- Jakarta EE (anteriormente Java EE): Plataforma para el desarrollo de aplicaciones empresariales
- Quarkus: Framework para aplicaciones Java optimizadas para Kubernetes
- Micronaut: Framework para microservicios y aplicaciones sin servidor (serverless)
Herramientas de Pruebas (Testing)
- JUnit: Framework para pruebas unitarias
- Mockito: Framework para la creación de objetos mock en pruebas
- AssertJ: Biblioteca para aserciones fluidas
- Selenium: Automatización de pruebas de interfaz de usuario
Java en el Proyecto
En el contexto de nuestro proyecto de sistema de feedback, Java se utiliza para implementar los siguientes microservicios:
- User Management: Gestión de usuarios, autenticación y autorización
- Feedback Request: Creación y gestión de solicitudes de feedback
- Feedback Response: Procesamiento de respuestas de feedback
Estos microservicios se implementan usando Spring Boot, que simplifica el desarrollo de aplicaciones Java, proporcionando configuraciones automáticas y un modelo de programación basado en convenciones.
Ejemplo de Implementación con Spring Boot
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
@HasType("ADMIN")
public Page<UserDTO> listUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.findUsers(name, PageRequest.of(page, size));
}
@PostMapping
@HasType("ADMIN")
public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO) {
UserDTO createdUser = userService.createUser(userDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
@GetMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PutMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<UserDTO> updateUser(
@PathVariable Long id,
@RequestBody @Valid UserDTO userDTO) {
return ResponseEntity.ok(userService.updateUser(id, userDTO));
}
@DeleteMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
Conclusión
Java es un lenguaje versátil y robusto que continúa siendo ampliamente utilizado en el desarrollo de aplicaciones empresariales, incluyendo sistemas basados en microservicios. Su tipado fuerte, orientación a objetos y ecosistema maduro lo convierten en una elección sólida para el desarrollo de aplicaciones complejas y de misión crítica.
En el contexto de nuestro proyecto, Java proporciona la base para la implementación de los principales microservicios, garantizando la confiabilidad, mantenibilidad y escalabilidad del sistema.