0% encontró este documento útil (0 votos)
2 vistas

java

Doc Java Resumen
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
2 vistas

java

Doc Java Resumen
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 104

Mutabilidad

Métodos en Java
Tipos de métodos en Java
Declaración de métodos
Llamada de métodos
Estructuras de datos Java
ArrayList
Declaración
Metodos
Ejemplos Aplicados
Añadir Elementos:
Acceder a Elementos:
Eliminar Elementos
Tamaño y Capacidad
Buscar Elementos
Convertir a Array
Operaciones Avanzadas
Hashtable
Características Principales:
Puntos Clave:
Consideraciones:
java.util.Random
java.lang.Math
java.util.concurrent.ThreadLocalRandom
java.security.SecureRandom
Usando HashTable
put(K key, V value)
Usando JOptionPane
showMessageDialog (Component parentComponent, Object message)
String showInputDialog(Object message)
showConfirmDialog
Combo JOptionPane
¿Qué es la programación orientada a objetos?
¿Por qué la programación orientada a objetos?
Clases y objetos
¿Qué son las clases y los objetos?
Clases en Java
Esqueleto de una clase
Modificadores de acceso
Métodos getter y setter
Paradigmas de la POO
Encapsulamiento
Abstracción
Herencia
Super()
Invocar el Constructor de la Clase Base
Acceder a Métodos y Variables de la Clase Base
Puntos Clave
Aplicando herencia caso BetPlay
Polimorfismo
Ejemplo de Sobrecarga de Métodos en Java
Ejemplo de Sobrescritura de Métodos en Java
Test Conocimiento
Patrones de diseño
SOLID
S - Single Responsibility Principle (SRP)
Mal diseño
Buen diseño (siguiendo el SRP)
O - Open/Closed Principle (OCP)
Mal diseño (violación del OCP)
Beneficios del OCP
L - Liskov Substitution Principle (LSP)
Beneficios del LSP
I - Interface Segregation Principle (ISP)
Mal diseño (violación del ISP)
Buen diseño (siguiendo el ISP)
Beneficios del ISP
D - Dependency Inversion Principle (DIP)
Mal diseño (violación del DIP)
Buen diseño (siguiendo el DIP)
Resumiendo....
Problema
Aplicando Principios SOLID
Principio de Responsabilidad Única (SRP)
Aplicando Principios SOLID
Principio de Responsabilidad Única (SRP)
Principio de Abierto/Cerrado (OCP)
Principio de Sustitución de Liskov (LSP)
Principio de Segregación de Interfaces (ISP)
Principio de Inversión de Dependencias (DIP)
Persistencia de Datos (Mysql)
¿Qué es JDBC?
Componentes Principales de JDBC
Configuración de controlador (MySQl)
Expresiones Lambda
Características de las Expresiones Lambda
Sintaxis de una Expresión Lambda
Ejemplos de Expresiones Lambda
Sin Parámetros:
Con un Parámetro:
Con Múltiples Parámetros:
Bloque de Código:
Uso de Expresiones Lambda
Iterar sobre una colección:
Explicación del Código
Ordenar Usando Comparator con Expresión Lambda
Consumer
Características de Consumer
Uso de Consumer con Expresiones Lambda
Ejemplo: Uso de Consumer con Expresiones Lambda
BiConsumer
Características de BiConsumer
Sintaxis de BiConsumer
Ejemplo de Uso de BiConsumer con Expresiones Lambda
Ejemplo: Procesar Pares Clave-Valor
Supplier
Características de Supplier
Sintaxis de Supplier
Ejemplo: Generar un Valor Aleatorio
Ejercicio:
Explicación del Código
Predícate
Características de Predicate
Métodos Comunes en Predicate
Sintaxis de una Expresión Lambda que Implementa Predicate
Ejemplos de Uso
1. Ejemplo Básico con Predicate
Explicación del Código
2. Ejemplo con Listas y Predicate
Explicación del Código
3. Combinación de Predicados
Explicación del Código
Ejemplo Completo con la Clase Persona
Stream
Características de los Streams
Componentes Principales de los Streams
Ejemplo Básico de Uso de Streams
Operaciones Comunes en Streams
1. filter
2. map
3. collect
4. forEach
5. reduce
Ejemplo Completo con la Clase Persona
Generar Ejecutable
Instalar en linux
Instalar maven windows
Probar configuracion de maven
Configuración del proyecto en Visual Studio Code

Mutabilidad
La mutabilidad se refiere a la capacidad de un objeto de cambiar su estado después de su
creación. En el contexto de programación, un objeto mutable es aquel cuyos valores internos
pueden ser modificados después de la creación del objeto. Un objeto inmutable no puede
cambiar su estado cuando se ha creado.
package com.trainer.mutabilidad;

public class Main {


public static void main(String[] args) {
String inmutableStr = "Hola";
inmutableStr = inmutableStr.concat(" Mundo");
System.out.println(inmutableStr);
}
}

Clases envolventes (Wrapper classes): Las clases como Integer, Double, etc., son inmutables.

Métodos en Java
Los métodos en Java son secciones de código diseñadas para ejecutar tareas específicas,
identificados por un nombre y capaces de recibir parámetros que les proporcionan la información
necesaria. Estos parámetros actúan como datos de entrada para el método, permitiéndole operar
con los valores recibidos.

Dentro del cuerpo del método, se pueden llevar a cabo diversas acciones, como operaciones
matemáticas, manipulación de datos o incluso llamadas a otros métodos. Una vez que el método
ha completado su tarea, puede devolver un resultado mediante la palabra clave "return" seguida
del valor deseado.

La capacidad de reutilización del código es una de las principales ventajas de los métodos en Java.
Al definir un método una vez, podemos invocarlo en diferentes partes del programa, evitando la
repetición innecesaria de código. Esto no solo simplifica la estructura del código, sino que también
facilita su mantenimiento y promueve un mayor modularidad en la aplicación.

Tipos de métodos en Java


· Métodos sin resultado: Estos métodos no retornan ningún valor. Su principal propósito es
ejecutar un conjunto de instrucciones o modificar el estado de un objeto.

· Métodos de retorno: Estos métodos entregan un valor al finalizar su ejecución. Este valor
puede ser de cualquier tipo de dato válido en Java, como números enteros, cadenas de texto,
booleanos, entre otros. Por ejemplo, podría ser el resultado de una operación aritmética.

· Métodos estáticos: Los métodos estáticos están asociados a la clase en lugar de una instancia
de la clase. Estos métodos se pueden invocar directamente sin la necesidad de crear un objeto.
Declaración de métodos

Llamada de métodos
Estructuras de datos Java
ArrayList
La clase ArrayList en Java permite almacenar datos en memoria de manera similar a los Arrays,
pero con la ventaja de que puede ajustar dinámicamente la cantidad de elementos almacenados,
eliminando la necesidad de declarar su tamaño previamente, como ocurre con los Arrays.

Declaración

ArrayList<T> nombreArrayList = new ArrayList<T>();

Ejemplo

ArrayList<String> nombreEmpleado = new ArrayList<String>();

Metodos
1. Añadir Elementos:

boolean add(E e) : Añade el elemento especificado al final de la lista.

void add(int index, E element) : Inserta el elemento especificado en la posición


especificada de la lista.

2. Acceder a Elementos:

E get(int index) : Devuelve el elemento en la posición especificada de la lista.

E set(int index, E element) : Reemplaza el elemento en la posición especificada con


el elemento especificado y devuelve el elemento antiguo.

3. Eliminar Elementos:

E remove(int index) : Elimina el elemento en la posición especificada y lo devuelve.

boolean remove(Object o) : Elimina la primera ocurrencia del elemento especificado


de la lista (si está presente) y devuelve true si se eliminó algún elemento.

void clear() : Elimina todos los elementos de la lista.

4. Tamaño y Capacidad:

int size() : Devuelve el número de elementos en la lista.

boolean isEmpty() : Devuelve true si la lista no contiene elementos.

5. Buscar Elementos:

boolean contains(Object o) : Devuelve true si la lista contiene el elemento


especificado.

int indexOf(Object o) : Devuelve el índice de la primera ocurrencia del elemento


especificado, o -1 si la lista no contiene el elemento.

int lastIndexOf(Object o) : Devuelve el índice de la última ocurrencia del elemento


especificado, o -1 si la lista no contiene el elemento.

6. Convertir a Array:
Object[] toArray() : Devuelve un array que contiene todos los elementos de la lista
en el orden adecuado.

<T> T[] toArray(T[] a) : Devuelve un array que contiene todos los elementos de la
lista en el orden adecuado; el tipo del array devuelto es del mismo tipo que el array
especificado.
7. Operaciones Avanzadas:

boolean addAll(Collection<? extends E> c) : Añade todos los elementos de la


colección especificada al final de la lista.

boolean addAll(int index, Collection<? extends E> c) : Inserta todos los


elementos de la colección especificada en la lista, comenzando en la posición
especificada.

boolean removeAll(Collection<?> c) : Elimina de la lista todos sus elementos que


están contenidos en la colección especificada.

boolean retainAll(Collection<?> c) : Retiene solo los elementos en la lista que


están contenidos en la colección especificada.

void ensureCapacity(int minCapacity) : Aumenta la capacidad de la lista de arreglos


para garantizar que pueda contener al menos el número de elementos especificado.

void trimToSize() : Reduce la capacidad de la instancia ArrayList actual a su


tamaño actual.

8. Clonación y Comparación:

Object clone() : Devuelve una copia superficial de esta instancia ArrayList .

boolean equals(Object o) : Compara el ArrayList especificado con este para la


igualdad.

9. Iteración:

Iterator<E> iterator() : Devuelve un iterador sobre los elementos en la lista en la


secuencia adecuada.

ListIterator<E> listIterator() : Devuelve un iterador de lista sobre los elementos


en la lista en la secuencia adecuada.

ListIterator<E> listIterator(int index) : Devuelve un iterador de lista de los


elementos en la lista, comenzando en la posición especificada en la lista.

Ejemplos Aplicados

Añadir Elementos:

boolean add(E e)
package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//--------------------------
list.add("Backend Java");
//--------------------------
System.out.println(list);
}
}

método añade "Backend Java" al final del ArrayList . La salida muestra que el ArrayList ahora
contiene un elemento.

void add(int index, E element)

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
//--------------------------
list.add(0, "Fundamentos");
//--------------------------
System.out.println(list);
}
}

método inserta "Fundamentos" en la posición 1 del ArrayList .

Acceder a Elementos:

get(int index)

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
//--------------------------
String elemento = list.get(0);
//--------------------------
System.out.println(elemento);
}
}

set(int index, E element)

Este método reemplaza el elemento en una posición especifica (list.set(0, "Programacion web");)

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
//--------------------------
list.set(0, "Programacion web");
//--------------------------
System.out.println(list);
}
}

Eliminar Elementos

remove(int index) método elimina el elemento en la posición especifica

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
//--------------------------
String eliminado = list.remove(1);
//--------------------------
System.out.println(eliminado);
System.out.println(list);
}
}

boolean remove(Object o) Este método elimina la primera ocurrencia del elemento


especificado en el parámetro del ArrayList . Devuelve true si el elemento fue eliminado.

package com.trainer.mutabilidad;

import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
//--------------------------
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
//--------------------------
System.out.println(result);
System.out.println(list);
}
}

void clear() método elimina todos los elementos del ArrayList , dejándolo vacío.

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
//--------------------------
list.clear();
//--------------------------
System.out.println(list);
}
}

Tamaño y Capacidad

int size() método devuelve el número de elementos en el ArrayList .

package com.trainer.mutabilidad;

import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
//------------------------------------
int size = list.size();
System.out.println(size); // Output: 2
//-----------------------------------
System.out.println(list);
}
}

boolean isEmpty() Este método devuelve true si el ArrayList está vacío, de lo contrario
devuelve false .

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
//-----------------------------------
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
//------------------------------------
System.out.println(list);
}
}
Buscar Elementos

boolean contains(Object o) Este método comprueba si el ArrayList contiene "El elemento".


Devuelve true si el elemento está presente.

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
//------------------------------------
boolean contains = list.contains("Mysql");
System.out.println(contains);
//-----------------------------------
System.out.println(list);
}
}

int indexOf(Object o) Este método devuelve el índice de la primera ocurrencia del elemento a
buscar. Si no se encuentra el elemento retorna -1

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
//-----------------------------------
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
//------------------------------------
System.out.println(list);
}
}

int lastIndexOf(Object o) Este método devuelve el índice de la última ocurrencia del


elemento a buscar, si no se encuentra el elemento retorna -1.

package com.trainer.mutabilidad;

import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
//------------------------------------
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
//-----------------------------------
System.out.println(list);
}
}
Convertir a Array

Object[] toArray() Este método convierte el ArrayList a un array de Object . La salida


muestra el contenido del ArrayList en forma de array.

package com.trainer.mutabilidad;
import java.util.*;
import java.util.ArrayList;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
//-----------------------------------
Object[] skills = list.toArray();
System.out.println(Arrays.toString(skills));
//------------------------------------
// System.out.println(list);
}
}

Operaciones Avanzadas
boolean addAll(Collection<? extends E> c) Este método añade todos los elementos de
otraLista al final del ArrayList original.

package com.trainer.mutabilidad;
import java.util.*;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
Object[] skills = list.toArray();
System.out.println(Arrays.toString(skills));
//------------------------------------
ArrayList<String> otraLista = new ArrayList<>(Arrays.asList("Python",
"Pseint"));
list.addAll(otraLista);
System.out.println(list);
//-----------------------------------
// System.out.println(list);
}
}

boolean addAll(int index, Collection<? extends E> c) Este método inserta todos los
elementos de otraLista en la posición 2 del ArrayList original.

package com.trainer.mutabilidad;
import java.util.*;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
Object[] skills = list.toArray();
System.out.println(Arrays.toString(skills));
ArrayList<String> otraLista = new ArrayList<>(Arrays.asList("Python",
"Pseint"));
// list.addAll(otraLista);
// System.out.println(list);
//-----------------------------------
list.addAll(0, otraLista);
System.out.println(list);
//------------------------------------
// System.out.println(list);
}
}

boolean removeAll(Collection<?> c) Este método elimina todos los elementos del


ArrayList original que también están en otraLista .

package com.trainer.mutabilidad;
import java.util.*;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
Object[] skills = list.toArray();
System.out.println(Arrays.toString(skills));

ArrayList<String> otraLista = new ArrayList<>(Arrays.asList("Python",


"Pseint"));
// list.addAll(otraLista);
// System.out.println(list);
//-----------------------------------
// list.addAll(0, otraLista);
// System.out.println(list);
//------------------------------------
list.removeAll(otraLista);
System.out.println(list);
//------------------------------------
// System.out.println(list);
}
}

boolean retainAll(Collection<?> c) Este método retiene solo los elementos en el


ArrayList original que están contenidos en la colección especificada.

package com.trainer.mutabilidad;
import java.util.*;

public class Main {


public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Backend ");
list.add(0, "Fundamentos");
String elemento = list.get(0);
System.out.println(elemento);
list.set(0, "Programacion web");
String eliminado = list.remove(1);
System.out.println(eliminado);
list.add("Pasteleria");
boolean result = list.remove("Pasteleria");
System.out.println(result);
System.out.println(list);
int size = list.size();
System.out.println(size); // Output: 2
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
boolean contains = list.contains("Mysql");
System.out.println(contains);
int index = list.indexOf("Postgres");
System.out.println(index); // Output: 0
list.add("Mysql");
int lastIndex = list.lastIndexOf("Mysql");
System.out.println(lastIndex); // Output: 2
Object[] skills = list.toArray();
System.out.println(Arrays.toString(skills));

ArrayList<String> otraLista = new ArrayList<>(Arrays.asList("Python",


"Pseint"));
list.addAll(otraLista);
// System.out.println(list);
//-----------------------------------
// list.addAll(0, otraLista);
// System.out.println(list);
//------------------------------------
// list.removeAll(otraLista);
// System.out.println(list);
//------------------------------------
list.retainAll(Arrays.asList("Python"));
System.out.println(list);
// System.out.println(list);
}
}

Hashtable
Las Hashtable en Java son una estructura de datos que implementa una tabla hash, la cual
permite almacenar pares de clave-valor y ofrece una manera eficiente de buscar valores
asociados a claves específicas. La clase Hashtable es parte del paquete java.util .

Características Principales:
1. Sincronización: Hashtable es sincronizada, lo que significa que es segura para su uso en
entornos multi-hilo. Sin embargo, esta sincronización puede afectar el rendimiento
comparado con colecciones no sincronizadas como HashMap .

2. No permite null : No permite claves ni valores null . Intentar insertar null como clave o
valor resultará en una excepción NullPointerException .

3. Implementación de la interfaz Map : Como otras implementaciones de Map , como


HashMap y TreeMap , Hashtable implementa la interfaz Map , proporcionando métodos
estándar para manipular el conjunto de datos.
Puntos Clave:
1. Creación: Hashtable<Integer, String> hashtable = new Hashtable<>();

2. Agregar Elementos: hashtable.put(1, "Manzana");

3. Obtener Elementos: hashtable.get(1);

4. Comprobar Existencia:

Clave: hashtable.containsKey(2);

Valor: hashtable.containsValue("Cereza");

5. Eliminar Elementos: hashtable.remove(3);

Consideraciones:
Uso en Aplicaciones Concurrentes: Debido a su naturaleza sincronizada, Hashtable puede
ser útil en aplicaciones donde múltiples hilos acceden y modifican la estructura de datos
simultáneamente.

Alternativas Modernas: Aunque Hashtable sigue siendo útil, en muchos casos es


preferible usar HashMap junto con sincronización manual o usar ConcurrentHashMap del
paquete java.util.concurrent para aplicaciones que requieren alta concurrencia y mejor
rendimiento.

java.util.Random
La clase Random es una de las formas más comunes y flexibles para generar números aleatorios.

import java.util.Random;

public class RandomExample {


public static void main(String[] args) {
Random random = new Random();

// Generar un número entero aleatorio


int randomInt = random.nextInt();
System.out.println("Número entero aleatorio: " + randomInt);

// Generar un número entero aleatorio entre 0 y 99


int randomIntBounded = random.nextInt(100);
System.out.println("Número entero aleatorio entre 0 y 99: " +
randomIntBounded);

// Generar un número flotante aleatorio entre 0.0 y 1.0


float randomFloat = random.nextFloat();
System.out.println("Número flotante aleatorio entre 0.0 y 1.0: " +
randomFloat);

// Generar un número doble aleatorio entre 0.0 y 1.0


double randomDouble = random.nextDouble();
System.out.println("Número doble aleatorio entre 0.0 y 1.0: " +
randomDouble);

// Generar un número booleano aleatorio


boolean randomBoolean = random.nextBoolean();
System.out.println("Número booleano aleatorio: " + randomBoolean);
}
}

java.lang.Math
public class MathRandomExample {
public static void main(String[] args) {
// Generar un número doble aleatorio entre 0.0 y 1.0
double randomDouble = Math.random();
System.out.println("Número doble aleatorio entre 0.0 y 1.0: " +
randomDouble);

// Generar un número entero aleatorio entre 0 y 99


int randomInt = (int) (Math.random() * 100);
System.out.println("Número entero aleatorio entre 0 y 99: " + randomInt);
}
}

java.util.concurrent.ThreadLocalRandom
La clase ThreadLocalRandom es recomendada para generar números aleatorios en entornos
multi-hilo.

import java.util.concurrent.ThreadLocalRandom;

public class ThreadLocalRandomExample {


public static void main(String[] args) {
// Generar un número entero aleatorio entre 0 (inclusive) y 100
(exclusivo)
int randomInt = ThreadLocalRandom.current().nextInt(0, 100);
System.out.println("Número entero aleatorio entre 0 y 99: " + randomInt);

// Generar un número doble aleatorio entre 0.0 y 1.0


double randomDouble = ThreadLocalRandom.current().nextDouble(0.0, 1.0);
System.out.println("Número doble aleatorio entre 0.0 y 1.0: " +
randomDouble);

// Generar un número largo aleatorio entre 0 (inclusive) y 1000


(exclusivo)
long randomLong = ThreadLocalRandom.current().nextLong(0, 1000);
System.out.println("Número largo aleatorio entre 0 y 999: " +
randomLong);

// Generar un número booleano aleatorio


boolean randomBoolean = ThreadLocalRandom.current().nextBoolean();
System.out.println("Número booleano aleatorio: " + randomBoolean);
}
}
java.security.SecureRandom
Para generar números aleatorios con fines de seguridad, como en criptografía, se debe usar
SecureRandom .

import java.security.SecureRandom;

public class SecureRandomExample {


public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom();

// Generar un número entero aleatorio


int randomInt = secureRandom.nextInt();
System.out.println("Número entero aleatorio: " + randomInt);

// Generar un número entero aleatorio entre 0 y 99


int randomIntBounded = secureRandom.nextInt(100);
System.out.println("Número entero aleatorio entre 0 y 99: " +
randomIntBounded);

// Generar un número flotante aleatorio entre 0.0 y 1.0


float randomFloat = secureRandom.nextFloat();
System.out.println("Número flotante aleatorio entre 0.0 y 1.0: " +
randomFloat);

// Generar un número doble aleatorio entre 0.0 y 1.0


double randomDouble = secureRandom.nextDouble();
System.out.println("Número doble aleatorio entre 0.0 y 1.0: " +
randomDouble);

// Generar un número booleano aleatorio


boolean randomBoolean = secureRandom.nextBoolean();
System.out.println("Número booleano aleatorio: " + randomBoolean);
}
}

java.util.Random : Buena para la mayoría de los usos generales.


java.lang.Math.random() : Fácil y rápida para obtener un double entre 0.0 y 1.0.
java.util.concurrent.ThreadLocalRandom : Ideal para aplicaciones multi-hilo.

java.security.SecureRandom : Recomendado para aplicaciones que requieren seguridad,


como criptografía.

Usando HashTable
put(K key, V value)

agrega pares clave-valor a la Hashtable .

package com.creativecode.hashtable;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
//----------------------------------------------
personas.put(GenerateUnique(), sc.nextLine());
//----------------------------------------------
System.out.println(personas);

} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
}

get(Object key) devuelve el valor asociado a la clave especificada.

package com.creativecode.hashtable;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();
try (Scanner sc = new Scanner(System.in)){
System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//-----------------------------------------------------------

} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

containsKey(Object key) comprueba si la Hashtable contiene la clave especificada.

package com.creativecode.hashtable;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//----------------containsKey--------------------------------
System.out.println(personas.containsKey(getLastNumber()));
//-----------------------------------------------------------
} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

size() devuelve el número de pares clave-valor en la Hashtable .

package com.creativecode.hashtable;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//----------------containsKey--------------------------------
System.out.println(personas.containsKey(getLastNumber()));
//-------------------size------------------------------------
System.out.println(personas.size());
//-----------------------------------------------------------

} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

keySet() devuelve un conjunto de todas las claves en la Hashtable .

package com.creativecode.hashtable;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//----------------containsKey--------------------------------
System.out.println(personas.containsKey(getLastNumber()));
//-------------------size------------------------------------
System.out.println(personas.size());
//--------------------keySet---------------------------------
System.out.println(personas.keySet());
personas.keySet().forEach( keyValue -> {
System.out.println(MessageFormat.format("Llave valor : {0}",
keyValue));
});
//-----------------------------------------------------------

} catch (Exception e) {
// TODO: handle exception
}
}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

values() devuelve una colección de todos los valores en la Hashtable .

package com.creativecode.hashtable;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//----------------containsKey--------------------------------
System.out.println(personas.containsKey(getLastNumber()));
//-------------------size------------------------------------
System.out.println(personas.size());
//--------------------keySet---------------------------------
System.out.println(personas.keySet());
personas.keySet().forEach( keyValue -> {
System.out.println(MessageFormat.format("Llave valor : {0}",
keyValue));
});
//----------------------values-------------------------------
System.out.println(personas.values());
personas.values().forEach( ValueData -> {
System.out.println(MessageFormat.format("Valor : {0}",
ValueData));
});
//-----------------------------------------------------------

} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

keys() (usando Enumeration )

package com.creativecode.hashtable;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

import com.creativecode.hashtable.StaticClass.Variables;

public class Main {


public static void main(String[] args) {

@SuppressWarnings("unused")
int valueNumber= 0;
Hashtable <Integer,String> personas = new Hashtable<>();
Variables.uniqueNumbers = new HashSet<>();

try (Scanner sc = new Scanner(System.in)){


System.out.println("Ingrese el nombre :");
personas.put(GenerateUnique(), sc.nextLine());
//----------------GET----------------------------------------
System.out.println(personas.get(getLastNumber()));
//----------------containsKey--------------------------------
System.out.println(personas.containsKey(getLastNumber()));
//-------------------size------------------------------------
System.out.println(personas.size());
//--------------------keySet---------------------------------
System.out.println(personas.keySet());
personas.keySet().forEach( keyValue -> {
System.out.println(MessageFormat.format("Llave valor : {0}",
keyValue));
});
//----------------------values-------------------------------
System.out.println(personas.values());
personas.values().forEach( ValueData -> {
System.out.println(MessageFormat.format("Valor : {0}",
ValueData));
});
//----------------------Enumeration-------------------------
Enumeration<Integer> claves = personas.keys();
while (claves.hasMoreElements()) {
int clave = claves.nextElement();
System.out.println("Clave (con Enumeration): " + clave);
}

} catch (Exception e) {
// TODO: handle exception
}

}
public static int GenerateUnique(){
int randomNumber = 0;
randomNumber = ThreadLocalRandom.current().nextInt(Variables.max);
Variables.uniqueNumbers.add(randomNumber);

return randomNumber;
}
public static int getLastNumber(){
List<Integer> numberList = new ArrayList<>(Variables.uniqueNumbers);
return numberList.get(numberList.size()-1);
}
}

Usando JOptionPane
showMessageDialog (Component
parentComponent, Object message)
Este método crea una ventana que muestra un mensaje entregado en el parámetro message. El
parámetro parentComponent es para indicar la ventana padre. En estos primeros tutoriales
usaremos null en este parámetro.
package com.creativecode.ui;

import javax.swing.JOptionPane;

public class Main {


public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hola programadores");
}
}

String showInputDialog(Object message)


Este método se presenta como una función que despliega una ventana con una caja de texto y
dos botones: Aceptar y Cancelar. Al presionar el botón de Aceptar, el usuario obtendrá un String
que corresponde al contenido de la caja de texto, devuelto por la función. En cambio, si el usuario
selecciona el botón de Cancelar, recibirá un valor nulo como resultado de la función.

package com.creativecode.ui;

import java.text.MessageFormat;

import javax.swing.JOptionPane;

public class Main {


public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hola programadores");
//----------------------
String nombre = JOptionPane.showInputDialog("Escriba su nombre :");
JOptionPane.showMessageDialog(null, MessageFormat.format("Nombre :
{0}",nombre));
}
}

showConfirmDialog
JOptionPane.showConfirmDialog(Componente padre, mensaje, titulo, tipo de
seleccion, tipo de mensaje, icono);

Componente sobre el que se abre el cuadro de diálogo (lo dejamos por defecto)

Mensaje que se mostrará en el cuadro de diálogo.

Título de la ventana del cuadro de diálogo.

Tipo de selección, que puede ser:

JOptionPane.OK_CANCEL_OPTION: con dos botones.

JOptionPane.YES_NO_OPTION: con dos botones.

JOptionPane.YES_NO_CANCEL_OPTION: con tres botones.

package com.creativecode.ui;

import java.text.MessageFormat;
import javax.swing.JOptionPane;

public class Main {


public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hola programadores");
//----------------------
String nombre = JOptionPane.showInputDialog("Escriba su nombre :");
JOptionPane.showMessageDialog(null, MessageFormat.format("Nombre :
{0}",nombre));
//----------------------
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
}
}

Combo JOptionPane

package com.creativecode.ui;

import java.text.MessageFormat;

import javax.swing.JOptionPane;

public class Main {


public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Hola programadores");
//----------------------
String nombre = JOptionPane.showInputDialog("Escriba su nombre :");
JOptionPane.showMessageDialog(null, MessageFormat.format("Nombre :
{0}",nombre));
//----------------------
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
JOptionPane.showConfirmDialog(null, "Mensaje", "Informacion",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
//---------------------
String[] options = {"Español", "Inglés", "Francés", "Alemán"};
Object defaultOption = options[3];
// Mostrar el cuadro de diálogo y obtener la selección del usuario
Object opcion = JOptionPane.showInputDialog(null, "mensaje", "",
JOptionPane.QUESTION_MESSAGE,null,options,defaultOption);
System.out.println("Idioma seleccionado: " + opcion);
}
}

¿Qué es la programación orientada a


objetos?
La Programación Orientada a Objetos (POO) es un modelo o estilo de programación que se basa
en el uso de clases y objetos. Este enfoque permite estructurar un programa de software en
componentes simples y reutilizables, representados por clases, de los cuales se crean instancias
individuales de objetos.

¿Por qué la programación orientada a objetos?


La Programación Orientada a Objetos (POO) toma inspiración de nuestra comprensión del mundo
que nos rodea. Si consideramos la creación de un sistema de gestión de bibliotecas como
ejemplo, en lugar de enfocarnos en algoritmos y estructuras de datos, la POO nos invita a pensar
en entidades presentes en la biblioteca, como libros, bibliotecarios y usuarios. En este enfoque,
cada una de estas entidades se convierte en un objeto con sus propias propiedades (datos) y
comportamientos (funcionalidades). Por ejemplo, un objeto "Libro" podría tener atributos como
título, autor y año de publicación, junto con métodos para obtener información sobre el libro,
prestarlo o devolverlo a la biblioteca.

La esencia de la POO reside en la interacción entre estos objetos. Pueden comunicarse


enviándose mensajes y colaborando para alcanzar un objetivo común. Por ejemplo, un objeto
"Usuario" podría enviar un mensaje al objeto "Libro" para solicitar un préstamo, y el libro
respondería actualizando su estado interno. La Programación Orientada a Objetos ofrece
beneficios como la reutilización de código, la organización y la facilidad de mantenimiento. Sigue
el principio de desarrollo de software conocido como DRY (Don't Repeat Yourself), que busca
evitar la duplicación de código y promover la eficiencia en la creación de programas. Además,
mediante la encapsulación y la abstracción, se evita el acceso no autorizado a los datos y la
exposición del código propietario.

Clases y objetos
El proceso de creación de programas orientados a objetos implica, de manera resumida, la
creación de clases y la posterior creación de objetos basados en estas clases. Las clases sirven
como el modelo a partir del cual se estructuran los datos y comportamientos del programa.

¿Qué son las clases y los objetos?


Una clase actúa como una plantilla genérica que define cómo serán los objetos de un tipo
específico. Por ejemplo, una clase que representa a los animales podría llamarse "Animal" y
tendría atributos como "tipo" y "edad" (que generalmente son propiedades). Además, incluiría una
serie de comportamientos que los animales pueden tener, como desplazarse o comer, los cuales
se implementan como métodos de la clase (funciones).

Un ejemplo básico de un objeto, como mencionamos anteriormente, podría ser un animal. Para
representar este objeto, creamos un atributo llamado "edad" que almacena la edad del animal.
Además, el animal puede envejecer, por lo que podríamos definir un método que se encarga de
actualizar la edad. En resumen, una clase se encarga de definir tanto los datos (como el atributo
"edad") como la lógica (como el método de envejecimiento) relacionados con muchos objetos en
un programa. La clase proporciona una definición global y genérica que se utiliza para crear
múltiples instancias de objetos. La siguiente imagen nos ayuda a entender mejor la diferencia
entre clases y objetos.

Clases en Java
Para la creación de clases en Java se recomienda Crear paquetes que permitan organizar cada una
de las clases que se van a usar en el desarrollo software.

Esqueleto de una clase

La estructura básica de una clase en Java se compone de los siguientes elementos:

Declaración de la clase: Se utiliza la palabra clave class seguida del nombre de la clase, en
este caso, " MiClase ". Por convención, el nombre de la clase comienza con una letra
mayúscula.

Atributos de la clase: Son variables que representan características o propiedades de la


clase. En el ejemplo, se declaran tres atributos: " atributo1 " de tipo String , " atributo2 "
de tipo int y " atributo3 " de tipo float . Estos atributos representan datos que pueden
ser almacenados en cada objeto de la clase.

Constructor: Es un método especial que se utiliza para crear e inicializar objetos de la clase.
En el ejemplo, se define un constructor público con el mismo nombre de la clase, " MiClase ",
y no realiza ninguna acción particular. Puede tener parámetros para recibir valores iniciales
de los atributos.

Métodos de la clase: Son funciones que definen el comportamiento de la clase. En el


ejemplo, se definen dos métodos. " metodo1() " es un método vacío que no realiza ninguna
acción. " metodo2() " es un método que devuelve una cadena de texto ("metodo2") cuando se
llama.

Los paquetes deben depender del paquete principal del proyecto


Para crear un paquete siga los siguientes pasos:

1.

2.

3.

4.
5.

Para el ejemplo practico se creara una clase llamada Equipo que contendrá la informacion de
todos los equipos de la liga de futbol colombiana. Siga los siguientes pasos:

1. Haga clic derecho sobre el paquete en el que se creara la clase. Para el caso practico se
creara en el paquete model.

2.

3.
4.

Modificadores de acceso

En Java, los modificadores de acceso se utilizan para establecer el nivel de acceso y visibilidad de
clases, métodos, constructores y atributos (variables de instancia) dentro de un programa. Los
modificadores de acceso controlan dónde se puede acceder y utilizar una clase, método o
variable.

Java ofrece cuatro modificadores de acceso principales:

1. public : El miembro (clase, método, variable) es accesible desde cualquier otra clase.

2. protected : El miembro es accesible dentro del mismo paquete y por las subclases en
cualquier paquete.

3. (default) [sin modificador]: Si no se especifica ningún modificador, el miembro es accesible


solo dentro del mismo paquete. Esto a veces se llama "package-private" o "paquete".

4. private : El miembro es accesible solo dentro de la clase en la que está declarado.

Métodos getter y setter

En Java, los métodos getter y setter son utilizados para acceder y modificar los valores de los
atributos privados de una clase. Estos métodos permiten el encapsulamiento de datos, una de las
características fundamentales de la programación orientada a objetos.

Paradigmas de la POO
Los principales paradigmas de la POO incluyen:

Encapsulamiento
El encapsulamiento es el concepto de ocultar los detalles internos de un objeto y exponer solo lo
necesario. Esto se logra mediante el uso de modificadores de acceso ( public , private ,
protected ) para controlar la visibilidad de los atributos y métodos de una clase. La idea es que
un objeto maneje su propio estado interno y que otros objetos interactúen con él solo a través de
métodos públicos.

public class Persona {


private String nombre; // Estado interno oculto
private int edad;
// Constructor
public Persona(String nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
// Métodos públicos para interactuar con el estado
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
if (edad > 0) { // Validación
this.edad = edad;
}
}
}

Abstracción
La abstracción consiste en simplificar la complejidad mediante la modelación de clases que
representan conceptos abstractos del mundo real, capturando solo los detalles esenciales. Las
clases abstractas y las interfaces se utilizan para definir estructuras de datos y comportamientos
comunes.

public abstract class Animal {


public abstract void hacerSonido();
}

public class Perro extends Animal {


@Override
public void hacerSonido() {
System.out.println("Guau guau");
}
}
public class Gato extends Animal {
@Override
public void hacerSonido() {
System.out.println("Miau miau");
}
}

Herencia
La herencia permite crear nuevas clases basadas en clases existentes. La nueva clase, llamada
subclase, hereda atributos y métodos de la clase base, permitiendo reutilizar y extender el código
existente.
public class Animal {
protected String nombre;

public void comer() {


System.out.println(nombre + " está comiendo");
}
}

public class Perro extends Animal {


public void ladrar() {
System.out.println(nombre + " está ladrando");
}
}

Super()

En Java, la palabra clave super se utiliza para referirse a la clase base inmediata de una clase
derivada. El uso de super() tiene dos propósitos principales:

1. Invocar el constructor de la clase base.

2. Acceder a métodos y variables de la clase base.

Invocar el Constructor de la Clase Base

Cuando una subclase se inicializa, es común que necesite inicializar algunos atributos definidos en
la clase base. Para ello, se usa super() para invocar el constructor de la clase base. Si no se
invoca explícitamente, Java automáticamente llama al constructor sin argumentos de la clase
base.

class Animal {
String nombre;

// Constructor de la clase base


public Animal(String nombre) {
this.nombre = nombre;
}
}

class Perro extends Animal {


String raza;

// Constructor de la clase derivada


public Perro(String nombre, String raza) {
super(nombre); // Invocación del constructor de la clase base
this.raza = raza;
}
}

public class Main {


public static void main(String[] args) {
Perro perro = new Perro("Max", "Labrador");
System.out.println(perro.nombre); // Salida: Max
System.out.println(perro.raza); // Salida: Labrador
}
}

Acceder a Métodos y Variables de la Clase Base

La palabra clave super también se puede utilizar para acceder a métodos y variables de la clase
base que han sido ocultados por la subclase.

class Animal {
public void hacerSonido() {
System.out.println("El animal hace un sonido");
}
}

class Perro extends Animal {


@Override
public void hacerSonido() {
System.out.println("El perro ladra");
}

public void mostrarSonidos() {


super.hacerSonido(); // Llama al método de la clase base
hacerSonido(); // Llama al método de la clase derivada
}
}

public class Main {


public static void main(String[] args) {
Perro perro = new Perro();
perro.mostrarSonidos();
}
}

Puntos Clave

Constructores: super() debe ser la primera línea en el constructor de la subclase si se


quiere invocar al constructor de la clase base.

Métodos y Variables: Se utiliza super para acceder a los métodos y variables de la clase
base cuando estos han sido sobreescritos en la subclase.

Constructores sin Argumentos: Si no se llama explícitamente a super() , Java llama


implícitamente al constructor sin argumentos de la clase base.

Aplicando herencia caso BetPlay

Los quipos de futbol pueden tener en su estructura interna jugadores, cuerpo técnico y masajistas
(Personal de recuperacion fisica).
Si observamos detenidamente todas las clases de la figura poseen atributos y métodos iguales.

Para dar solución a esta problemática acudimos al factor común el cual consiste en tomar los
atributos iguales y crear una clase principal que reuna estos atributos.
Polimorfismo
El polimorfismo permite a las clases derivadas ser tratadas como si fueran instancias de su clase
base. Hay dos tipos principales de polimorfismo: en tiempo de compilación (sobrecarga de
métodos) y en tiempo de ejecución (sobreescritura de métodos).

Ejemplo de Sobrecarga de Métodos en Java

public class Calculadora {


public int sumar(int a, int b) {
return a + b;
}

public double sumar(double a, double b) {


return a + b;
}
}

Ejemplo de Sobrescritura de Métodos en Java

public class Animal {


public void hacerSonido() {
System.out.println("El animal hace un sonido");
}
}

public class Perro extends Animal {


@Override
public void hacerSonido() {
System.out.println("El perro ladra");
}
}

Test Conocimiento
¿Cuál de las siguientes opciones define correctamente la encapsulación en Java?

A. La capacidad de una clase para heredar características de otra clase.


B. El mecanismo de definir múltiples métodos con el mismo nombre pero diferentes parámetros.
C. El proceso de ocultar los detalles internos de una clase y exponer solo lo necesario.
D. La capacidad de un objeto de tomar muchas formas.

¿Cuál es el propósito de la palabra clave super en Java?

A. Crear una nueva instancia de una clase.


B. Acceder a métodos y variables de la clase base desde una subclase.
C. Definir un método que no puede ser sobreescrito.
D. Comparar dos objetos para igualdad.

¿Qué modificador de acceso permite que un miembro de una clase sea accesible solo dentro del
mismo paquete y por las subclases en cualquier paquete?
A. public
B. private
C. protected
D. (default) [sin modificador]

¿Cuál de las siguientes afirmaciones sobre la herencia es correcta?

A. Una clase derivada puede heredar de múltiples clases base.


B. Los constructores de la clase base no son accesibles en la clase derivada.
C. Una clase derivada hereda los constructores de la clase base.
D. Una clase derivada puede sobreescribir métodos de la clase base.

¿Cuál de las siguientes es una característica del polimorfismo en Java?

A. Permite que una clase tenga múltiples constructores.


B. Permite definir una interfaz con métodos abstractos.
C. Permite tratar objetos de diferentes clases de la misma manera a través de una clase base
común.
D. Permite sobrecargar operadores.

¿Cuál es la salida del siguiente código Java?

class Animal {
public void hacerSonido() {
System.out.println("El animal hace un sonido");
}
}

class Perro extends Animal {


@Override
public void hacerSonido() {
System.out.println("El perro ladra");
}
}

public class Main {


public static void main(String[] args) {
Animal miAnimal = new Perro();
miAnimal.hacerSonido();
}
}

A. El animal hace un sonido


B. El perro ladra
C. Error de compilación
D. No hay salida

¿Cuál de los siguientes es verdadero acerca de las interfaces en Java?

A. Una clase puede implementar múltiples interfaces.


B. Una clase puede extender múltiples interfaces.
C. Una interfaz puede implementar otra interfaz.
D. Una interfaz puede tener métodos no abstractos.

¿Cuál es la salida del siguiente código Java?


class Persona {
private String nombre;

public Persona(String nombre) {


this.nombre = nombre;
}

public String getNombre() {


return nombre;
}
}

class Empleado extends Persona {


private int salario;

public Empleado(String nombre, int salario) {


super(nombre);
this.salario = salario;
}

public int getSalario() {


return salario;
}
}

public class Main {


public static void main(String[] args) {
Empleado emp = new Empleado("Carlos", 5000);
System.out.println(emp.getNombre() + " tiene un salario de " +
emp.getSalario());
}
}

A. Carlos tiene un salario de 5000


B. Carlos tiene un salario de 0
C. Error de compilación
D. Excepción en tiempo de ejecución

Patrones de diseño
Un patrón de diseño es una solución reusable a problemas comunes en el diseño de software. Se
trata de descripciones o plantillas de cómo resolver un problema que se presenta repetidamente
en el desarrollo de software. Los patrones de diseño no son piezas de código concreto, sino más
bien formas generales de organizar el código y las interacciones entre objetos y clases.

Existen varios tipos de patrones de diseño, y se pueden clasificar en tres categorías principales:

1. Patrones Creacionales:

Factory Method: Define una interfaz para crear un objeto, pero permite a las subclases
alterar el tipo de objetos que se crearán.

Abstract Factory: Provee una interfaz para crear familias de objetos relacionados o
dependientes sin especificar sus clases concretas.
Singleton: Asegura que una clase tenga solo una instancia y proporciona un punto de
acceso global a ella.

Builder: Separa la construcción de un objeto complejo de su representación para poder


crear diferentes representaciones.

Prototype: Permite la creación de nuevos objetos copiando instancias existentes.


2. Patrones Estructurales:

Adapter: Permite que clases con interfaces incompatibles trabajen juntas mediante una
interfaz de adaptación.

Decorator: Añade responsabilidades a un objeto de manera dinámica.

Facade: Provee una interfaz simplificada a un sistema complejo.

Composite: Compone objetos en estructuras de árbol para representar jerarquías de


partes y todo.

Proxy: Proporciona un sustituto o marcador de posición para otro objeto para controlar
el acceso a él.

3. Patrones de Comportamiento:

Observer: Define una dependencia uno a muchos entre objetos para que cuando uno
cambie su estado, todos sus dependientes sean notificados y actualizados
automáticamente.

Strategy: Define una familia de algoritmos, encapsula cada uno, y los hace
intercambiables.

Command: Encapsula una solicitud como un objeto, permitiendo parametrizar clientes


con colas de solicitudes, solicitudes de registro y operaciones que pueden deshacerse.

Iterator: Proporciona una manera de acceder secuencialmente a los elementos de un


objeto agregado sin exponer su representación subyacente.

State: Permite que un objeto altere su comportamiento cuando su estado interno


cambia.

SOLID
SOLID se refiere a cinco principios de diseño de software orientado a objetos que buscan mejorar
la calidad, mantenibilidad y escalabilidad del código. Estos principios son los siguientes:

S - Single Responsibility Principle (SRP)


Un módulo o clase debe tener una, y solo una, razón para cambiar, lo que significa que debe tener
una sola responsabilidad o propósito.

Ejemplo

Supongamos que estamos desarrollando una aplicación para la gestión de empleados. En un mal
diseño, podríamos tener una clase Employee que no solo gestione la información del empleado,
sino que también maneje la lógica de persistencia (guardar, actualizar y eliminar empleados en
una base de datos).
Mal diseño

public class Employee {


private String id;
private String name;
private double salary;

public Employee(String id, String name, double salary) {


this.id = id;
this.name = name;
this.salary = salary;
}

// Getters y setters

public void save() {


// Código para guardar el empleado en la base de datos
}

public void update() {


// Código para actualizar el empleado en la base de datos
}

public void delete() {


// Código para eliminar el empleado de la base de datos
}
}

Buen diseño (siguiendo el SRP)


Para adherirse al SRP, debemos separar las responsabilidades en clases distintas:

1. Clase Employee : Solo maneja la información del empleado.

2. Clase EmployeeRepository : Maneja la lógica de persistencia del empleado.

// Clase Employee que maneja solo la información del empleado


public class Employee {
private String id;
private String name;
private double salary;

public Employee(String id, String name, double salary) {


this.id = id;
this.name = name;
this.salary = salary;
}

// Getters y setters
}
// Clase EmployeeRepository que maneja la persistencia de los empleados
public class EmployeeRepository {
public void save(Employee employee) {
// Código para guardar el empleado en la base de datos
}

public void update(Employee employee) {


// Código para actualizar el empleado en la base de datos
}

public void delete(Employee employee) {


// Código para eliminar el empleado de la base de datos
}
}

Uso clases

public class Main {


public static void main(String[] args) {
Employee employee = new Employee("1", "John Doe", 50000);
EmployeeRepository repository = new EmployeeRepository();

repository.save(employee);
// Otros métodos de repository como update() y delete()
}
}

O - Open/Closed Principle (OCP)


Este principio establece que las entidades de software (clases, módulos, funciones, etc.) deben
estar abiertas para su extensión pero cerradas para su modificación. En otras palabras, debes
poder añadir nuevas funcionalidades a una entidad de software existente sin modificar su código
fuente.

Supongamos que estamos desarrollando un sistema de cálculo de salarios para diferentes tipos
de empleados (por ejemplo, empleados a tiempo completo y empleados contratados). Queremos
que el sistema sea extensible sin necesidad de modificar el código existente cuando se agregue
un nuevo tipo de empleado.

Mal diseño (violación del OCP)


En este caso, podríamos tener una clase SalaryCalculator que tiene lógica específica para cada
tipo de empleado:

public class Employee {


private String id;
private String name;
private double baseSalary;
private String type; // "FULL_TIME" or "CONTRACTOR"
public Employee(String id, String name, double baseSalary, String type) {
this.id = id;
this.name = name;
this.baseSalary = baseSalary;
this.type = type;
}

// Getters y setters
}

public class SalaryCalculator {


public double calculateSalary(Employee employee) {
if (employee.getType().equals("FULL_TIME")) {
return employee.getBaseSalary();
} else if (employee.getType().equals("CONTRACTOR")) {
return employee.getBaseSalary() * 0.8;
}
return 0;
}
}

Este diseño viola el OCP porque cada vez que se añade un nuevo tipo de empleado, se
necesita modificar la clase SalaryCalculator .

Buen diseño (siguiendo el OCP)

Para adherirse al OCP, se debe utilizar la herencia y el polimorfismo. Cada tipo de


empleado debe tener su propia

implementación del cálculo de salario.

Clase Employee : Clase base abstracta para empleados.

Clases concretas: FullTimeEmployee y ContractorEmployee que extienden Employee .

Interfaz SalaryCalculator : Define el método de cálculo de salario.

// Clase base abstracta para empleados


public abstract class Employee {
private String id;
private String name;
private double baseSalary;

public Employee(String id, String name, double baseSalary) {


this.id = id;
this.name = name;
this.baseSalary = baseSalary;
}

public double getBaseSalary() {


return baseSalary;
}

// Método abstracto para calcular el salario


public abstract double calculateSalary();
}

// Empleado a tiempo completo


public class FullTimeEmployee extends Employee {
public FullTimeEmployee(String id, String name, double baseSalary) {
super(id, name, baseSalary);
}

@Override
public double calculateSalary() {
return getBaseSalary();
}
}

// Empleado contratado
public class ContractorEmployee extends Employee {
public ContractorEmployee(String id, String name, double baseSalary) {
super(id, name, baseSalary);
}

@Override
public double calculateSalary() {
return getBaseSalary() * 0.8;
}
}

// Clase para calcular el salario (interfaz opcional si es necesario)


public interface SalaryCalculator {
double calculateSalary(Employee employee);
}

// Implementación de SalaryCalculator
public class DefaultSalaryCalculator implements SalaryCalculator {
@Override
public double calculateSalary(Employee employee) {
return employee.calculateSalary();
}
}
public class Main {
public static void main(String[] args) {
Employee fullTimeEmployee = new FullTimeEmployee("1", "John Doe", 50000);
Employee contractorEmployee = new ContractorEmployee("2", "Jane Smith",
40000);

SalaryCalculator calculator = new DefaultSalaryCalculator();

System.out.println("Full Time Employee Salary: " +


calculator.calculateSalary(fullTimeEmployee));
System.out.println("Contractor Employee Salary: " +
calculator.calculateSalary(contractorEmployee));
}
}

Beneficios del OCP


Extensibilidad: Para agregar un nuevo tipo de empleado, solo necesitas crear una nueva
clase que extienda Employee y sobrescribir el método calculateSalary() .

Mantenibilidad: No es necesario modificar el código existente para soportar nuevos tipos de


empleados, lo que reduce el riesgo de introducir errores.

Polimorfismo: Aprovecha el polimorfismo para calcular los salarios de manera uniforme a


través de diferentes tipos de empleados.

L - Liskov Substitution Principle (LSP)


Este principio establece que los objetos de una clase derivada deben poder ser reemplazados por
objetos de la clase base sin alterar el correcto funcionamiento del programa. Es decir, si S es una
subclase de T, los objetos de tipo T en un programa deben poder ser reemplazados por objetos
de tipo S sin afectar adversamente el comportamiento del programa.

Supongamos que estamos desarrollando una aplicación para un zoológico y tenemos una clase
Bird y sus subclases. Queremos asegurarnos de que cualquier subclase de Bird pueda ser
usada donde sea que se use la clase Bird sin afectar la funcionalidad del programa.

Mal diseño (violación del LSP)

public class Bird {


public void fly() {
System.out.println("Flying");
}
}

public class Sparrow extends Bird {


// Hereda el método fly() de Bird
}

public class Penguin extends Bird {


@Override
public void fly() {
// Los pingüinos no pueden volar, esto viola el LSP
throw new UnsupportedOperationException("Penguins can't fly");
}
}

public class Zoo {


public void makeBirdFly(Bird bird) {
bird.fly();
}

public static void main(String[] args) {


Bird sparrow = new Sparrow();
Bird penguin = new Penguin();

Zoo zoo = new Zoo();


zoo.makeBirdFly(sparrow); // Funciona bien
zoo.makeBirdFly(penguin); // Lanza una excepción
}
}

En este diseño, la clase Penguin viola el LSP porque su implementación del método fly() no es
consistente con la clase base Bird . Esto puede llevar a comportamientos inesperados o errores
en tiempo de ejecución.

Buen diseño (siguiendo el LSP)

Para adherirse al LSP, podemos introducir una jerarquía de clases más adecuada que refleje
correctamente las capacidades de las diferentes aves.

// Clase base abstracta para todas las aves


public abstract class Bird {
private String name;

public Bird(String name) {


this.name = name;
}

public String getName() {


return name;
}

public abstract void move();


}

// Clase para las aves que vuelan


public class FlyingBird extends Bird {
public FlyingBird(String name) {
super(name);
}

@Override
public void move() {
fly();
}

public void fly() {


System.out.println(getName() + " is flying");
}
}

// Clase para las aves que no vuelan


public class NonFlyingBird extends Bird {
public NonFlyingBird(String name) {
super(name);
}

@Override
public void move() {
walk();
}

public void walk() {


System.out.println(getName() + " is walking");
}
}

// Subclases específicas de aves


public class Sparrow extends FlyingBird {
public Sparrow(String name) {
super(name);
}
}

public class Penguin extends NonFlyingBird {


public Penguin(String name) {
super(name);
}
}

// Clase Zoo que utiliza la clase Bird


public class Zoo {
public void makeBirdMove(Bird bird) {
bird.move();
}

public static void main(String[] args) {


Bird sparrow = new Sparrow("Sparrow");
Bird penguin = new Penguin("Penguin");

Zoo zoo = new Zoo();


zoo.makeBirdMove(sparrow); // Sparrow is flying
zoo.makeBirdMove(penguin); // Penguin is walking
}
}
Beneficios del LSP
Consistencia: Todas las subclases de Bird pueden ser usadas de manera intercambiable
sin afectar el comportamiento esperado del programa.

Claridad: Las responsabilidades de cada clase están claramente definidas y reflejan las
capacidades reales de las aves.

Extensibilidad: Es fácil agregar nuevas subclases de Bird sin necesidad de modificar el


código existente, siempre y cuando se sigan las reglas establecidas por las clases base.

I - Interface Segregation Principle (ISP)


Este principio establece que los clientes no deberían verse obligados a depender de interfaces que
no utilizan. Es mejor tener muchas interfaces específicas para clientes en lugar de una interfaz
general.

Mal diseño (violación del ISP)


Supongamos que tenemos una interfaz Worker que define métodos para diferentes tipos de
trabajadores en una empresa, incluidos los métodos para tareas que algunos trabajadores no
realizan:

public interface Worker {


void work();
void eat();
void sleep();
}

public class Developer implements Worker {


@Override
public void work() {
System.out.println("Developing software");
}

@Override
public void eat() {
System.out.println("Eating lunch");
}

@Override
public void sleep() {
System.out.println("Sleeping at home");
}
}

public class Robot implements Worker {


@Override
public void work() {
System.out.println("Assembling parts");
}

@Override
public void eat() {
// Los robots no comen, esto no tiene sentido
throw new UnsupportedOperationException("Robots don't eat");
}

@Override
public void sleep() {
// Los robots no duermen, esto no tiene sentido
throw new UnsupportedOperationException("Robots don't sleep");
}
}

En este diseño, la interfaz Worker fuerza a que todas las implementaciones incluyan métodos que
no son aplicables a ciertos tipos de trabajadores, como los robots.

Buen diseño (siguiendo el ISP)


Para adherirse al ISP, podemos dividir la interfaz Worker en varias interfaces más específicas que
agrupen métodos relacionados.

// Interfaz para trabajar


public interface Workable {
void work();
}

// Interfaz para comer


public interface Eatable {
void eat();
}

// Interfaz para dormir


public interface Sleepable {
void sleep();
}

// Clase para desarrolladores que implementan todas las interfaces necesarias


public class Developer implements Workable, Eatable, Sleepable {
@Override
public void work() {
System.out.println("Developing software");
}

@Override
public void eat() {
System.out.println("Eating lunch");
}

@Override
public void sleep() {
System.out.println("Sleeping at home");
}
}

// Clase para robots que solo implementan la interfaz Workable


public class Robot implements Workable {
@Override
public void work() {
System.out.println("Assembling parts");
}
}

// Clase para la oficina que puede manejar diferentes tipos de trabajadores


public class Office {
private Workable workable;
private Eatable eatable;
private Sleepable sleepable;

public Office(Workable workable) {


this.workable = workable;
}

public void setEatable(Eatable eatable) {


this.eatable = eatable;
}

public void setSleepable(Sleepable sleepable) {


this.sleepable = sleepable;
}

public void manageWork() {


workable.work();
}

public void manageLunch() {


if (eatable != null) {
eatable.eat();
}
}

public void manageSleep() {


if (sleepable != null) {
sleepable.sleep();
}
}
}

// Clase principal para ejecutar el código


public class Main {
public static void main(String[] args) {
Developer developer = new Developer();
Robot robot = new Robot();

Office office = new Office(developer);


office.setEatable(developer);
office.setSleepable(developer);
office.manageWork(); // Developing software
office.manageLunch(); // Eating lunch
office.manageSleep(); // Sleeping at home

office = new Office(robot);


office.manageWork(); // Assembling parts
office.manageLunch(); // No output, robots don't eat
office.manageSleep(); // No output, robots don't sleep
}
}

Beneficios del ISP


Claridad: Las interfaces pequeñas y específicas son más fáciles de entender y mantener.

Flexibilidad: Las clases solo implementan las interfaces que realmente necesitan, evitando la
implementación de métodos no aplicables.

Reusabilidad: Los componentes se pueden reutilizar de manera más efectiva, ya que solo
dependen de las interfaces necesarias.

D - Dependency Inversion Principle (DIP)


Este principio establece que las clases de alto nivel no deberían depender de clases de bajo nivel.
Ambas deberían depender de abstracciones. Además, las abstracciones no deberían depender de
los detalles. Los detalles deberían depender de las abstracciones.

Mal diseño (violación del DIP)


Supongamos que tenemos una clase Database que se conecta directamente a una base de datos
específica (por ejemplo, MySQL). Además, tenemos una clase UserService que depende
directamente de Database .

// Clase que se conecta a una base de datos MySQL


public class MySQLDatabase {
public void connect() {
System.out.println("Connecting to MySQL database...");
}

public void disconnect() {


System.out.println("Disconnecting from MySQL database...");
}

public void getData() {


System.out.println("Fetching data from MySQL database...");
}
}

// Clase de servicio que depende directamente de MySQLDatabase


public class UserService {
private MySQLDatabase database;

public UserService() {
this.database = new MySQLDatabase();
}

public void displayUserData() {


database.connect();
database.getData();
database.disconnect();
}
}

// Clase principal para ejecutar el código


public class Main {
public static void main(String[] args) {
UserService userService = new UserService();
userService.displayUserData();
}
}

En este diseño, UserService depende directamente de MySQLDatabase , lo que hace que sea
difícil cambiar la implementación de la base de datos sin modificar UserService .

Buen diseño (siguiendo el DIP)


Para adherirse al DIP, debemos introducir una abstracción (una interfaz) y hacer que
UserService dependa de esta abstracción en lugar de una implementación concreta.

// Interfaz para la base de datos


public interface Database {
void connect();
void disconnect();
void getData();
}

// Implementación de MySQLDatabase que cumple con la interfaz Database


public class MySQLDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to MySQL database...");
}

@Override
public void disconnect() {
System.out.println("Disconnecting from MySQL database...");
}

@Override
public void getData() {
System.out.println("Fetching data from MySQL database...");
}
}

// Implementación de OracleDatabase que cumple con la interfaz Database


public class OracleDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to Oracle database...");
}

@Override
public void disconnect() {
System.out.println("Disconnecting from Oracle database...");
}
@Override
public void getData() {
System.out.println("Fetching data from Oracle database...");
}
}

// Clase de servicio que depende de la interfaz Database


public class UserService {
private Database database;

// Constructor que acepta cualquier implementación de Database


public UserService(Database database) {
this.database = database;
}

public void displayUserData() {


database.connect();
database.getData();
database.disconnect();
}
}

// Clase principal para ejecutar el código


public class Main {
public static void main(String[] args) {
Database mySQLDatabase = new MySQLDatabase();
UserService userService1 = new UserService(mySQLDatabase);
userService1.displayUserData();

Database oracleDatabase = new OracleDatabase();


UserService userService2 = new UserService(oracleDatabase);
userService2.displayUserData();
}
}

Resumiendo....
Principio de Responsabilidad Única (SRP): Cada clase debe tener una sola responsabilidad o
motivo para cambiar.

Principio de Abierto/Cerrado (OCP): Las clases deben estar abiertas para extensión, pero
cerradas para modificación. Es decir, deberías poder añadir nuevas funcionalidades sin cambiar el
código existente.

Principio de Sustitución de Liskov (LSP): Las subclases deben ser reemplazables por sus clases
base sin alterar el comportamiento del programa. Las subclases deben poder usarse en lugar de
las clases base sin problemas.

Principio de Segregación de Interfaces (ISP): Los clientes no deben verse obligados a depender
de interfaces que no usan. Es mejor tener interfaces específicas y pequeñas.
Principio de Inversión de Dependencias (DIP): Las clases de alto nivel no deben depender de
clases de bajo nivel. Ambas deben depender de abstracciones. Las abstracciones no deben
depender de detalles; los detalles deben depender de abstracciones.

Problema
crear un programa simple de una tienda en línea, donde aplicaremos todos los principios SOLID.
Imaginemos que tenemos un sistema donde los clientes pueden realizar pedidos y los pedidos se
pueden pagar utilizando diferentes métodos de pago.

// Clase Producto
class Product {
private String name;
private double price;

public Product(String name, double price) {


this.name = name;
this.price = price;
}

public double getPrice() {


return price;
}

public String getName() {


return name;
}
}

// Clase Pedido
class Order {
private List<Product> products;

public Order() {
products = new ArrayList<>();
}

public void addProduct(Product product) {


products.add(product);
}

public double calculateTotal() {


double total = 0;
for (Product product : products) {
total += product.getPrice();
}
return total;
}
}

// Clase Pago
class Payment {
public void pay(Order order) {
System.out.println("Paying " + order.calculateTotal());
}
}

public class OnlineStore {


public static void main(String[] args) {
Product product1 = new Product("Product 1", 10.0);
Product product2 = new Product("Product 2", 15.0);

Order order = new Order();


order.addProduct(product1);
order.addProduct(product2);

Payment payment = new Payment();


payment.pay(order);
}
}

Aplicando Principios SOLID


Principio de Responsabilidad Única (SRP)

Cada clase debe tener una sola responsabilidad. Vamos a separar las responsabilidades de cálculo
de total y de pago.

// Clase Pedido
class Order {
private List<Product> products;

public Order() {
products = new ArrayList<>();
}

public void addProduct(Product product) {


products.add(product);
}

public List<Product> getProducts() {


return products;
}
}

// Clase Calculadora de Total


class OrderCalculator {
public double calculateTotal(Order order) {
double total = 0;
for (Product product : order.getProducts()) {
total += product.getPrice();
}
return total;
}
}
Aplicando Principios SOLID
Principio de Responsabilidad Única (SRP)

Cada clase debe tener una sola responsabilidad. Vamos a separar las responsabilidades de cálculo
de total y de pago.

// Clase Pedido
class Order {
private List<Product> products;

public Order() {
products = new ArrayList<>();
}

public void addProduct(Product product) {


products.add(product);
}

public List<Product> getProducts() {


return products;
}
}

// Clase Calculadora de Total


class OrderCalculator {
public double calculateTotal(Order order) {
double total = 0;
for (Product product : order.getProducts()) {
total += product.getPrice();
}
return total;
}
}

Principio de Abierto/Cerrado (OCP)

Vamos a permitir la extensión del método de pago sin modificar la clase Payment .

// Interfaz PaymentMethod
interface PaymentMethod {
void pay(double amount);
}

// Implementación de Tarjeta de Crédito


class CreditCardPayment implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("Paying with credit card: " + amount);
}
}

// Implementación de PayPal
class PayPalPayment implements PaymentMethod {
@Override
public void pay(double amount) {
System.out.println("Paying with PayPal: " + amount);
}
}

Principio de Sustitución de Liskov (LSP)

Las clases de pago deben ser intercambiables sin afectar el programa.

Principio de Segregación de Interfaces (ISP)

Creamos interfaces pequeñas y específicas si fuese necesario, pero en este caso ya lo hemos
hecho con PaymentMethod .

Principio de Inversión de Dependencias (DIP)

Las clases de alto nivel ( OrderProcessor ) no deben depender de clases de bajo nivel
( CreditCardPayment ), sino de abstracciones ( PaymentMethod ).

// Clase Procesadora de Pedidos


class OrderProcessor {
private OrderCalculator calculator;
private PaymentMethod paymentMethod;

public OrderProcessor(OrderCalculator calculator, PaymentMethod


paymentMethod) {
this.calculator = calculator;
this.paymentMethod = paymentMethod;
}

public void process(Order order) {


double amount = calculator.calculateTotal(order);
paymentMethod.pay(amount);
}
}

public class OnlineStore {


public static void main(String[] args) {
Product product1 = new Product("Product 1", 10.0);
Product product2 = new Product("Product 2", 15.0);

Order order = new Order();


order.addProduct(product1);
order.addProduct(product2);

OrderCalculator calculator = new OrderCalculator();


PaymentMethod paymentMethod = new PayPalPayment(); // O podemos usar
CreditCardPayment

OrderProcessor processor = new OrderProcessor(calculator, paymentMethod);


processor.process(order);
}
}
patrones de diseño son soluciones específicas a problemas específicos en el diseño de software,
los principios SOLID son directrices generales para estructurar y organizar tu código de manera
efectiva. Ambos conceptos son importantes y complementarios en el desarrollo de software

Persistencia de Datos (Mysql)


¿Qué es JDBC?
JDBC (Java Database Connectivity) es una API (Interfaz de Programación de Aplicaciones) en Java
que permite a los desarrolladores conectar sus aplicaciones Java a una base de datos. JDBC
proporciona un conjunto estándar de interfaces y clases que permiten ejecutar operaciones SQL,
como consultas, actualizaciones y eliminación de datos, directamente desde un programa Java.

Componentes Principales de JDBC


1. Driver Manager: Gestiona una lista de controladores de bases de datos. Selecciona un
controlador apropiado de la lista de controladores cuando se hace una conexión a la base de
datos.

2. Driver: Una interfaz que maneja las comunicaciones con el servidor de la base de datos.
Cada base de datos necesita su propio controlador.

3. Connection: Una interfaz que proporciona métodos para trabajar con la conexión a la base
de datos, como crear sentencias y administrar transacciones.

4. Statement: Una interfaz que representa una sentencia SQL que se puede ejecutar contra la
base de datos. Tiene subinterfaces como PreparedStatement (para sentencias SQL
precompiladas) y CallableStatement (para llamadas a procedimientos almacenados).

5. ResultSet: Una interfaz que representa el conjunto de resultados devueltos por una
sentencia SQL, permitiendo iterar sobre los datos obtenidos de una consulta.

6. SQLException: Una clase que maneja cualquier error que ocurra en el acceso a la base de
datos

Configuración de controlador (MySQl)


1. Cree un nuevo proyecto llamado Videogames

2. Cambie el nombre de la clase principal Main a Videogames

3. Instale el controlador mysql : Ingrese a la pagina oficial de Maven Repository https://mvnrepo


sitory.com/ en el buscador escriba Mysql
2. En el pom.xml pegar la etiqueta dependency de importacion de mysql en el grupo de
dependecies, si dependencies no esta creada se debe crear manualmente.
Conexión a la base de Datos
String url = "jdbc:mysql://localhost:3306/mydatabase";
String user = "root";
String password = "password";

jdbc:mysql:// : Este es el protocolo que indica que estás utilizando JDBC para conectarte a
una base de datos MySQL.

localhost : Este es el hostname o la dirección IP del servidor donde está alojada la base de
datos. En este caso, localhost se refiere a la máquina local donde se está ejecutando el
código.

3306 : Este es el número de puerto en el cual el servidor MySQL está escuchando las
conexiones. El puerto por defecto para MySQL es 3306 .

mydatabase : Este es el nombre de la base de datos a la que te estás conectando. Debe ser
reemplazado por el nombre real de tu base de datos.

user : Este es el nombre de usuario que se utiliza para autenticarse en la base de datos. En
este ejemplo, el usuario es root , que es el usuario administrador por defecto en MySQL. En
un entorno de producción, generalmente utilizarás un nombre de usuario con privilegios
más limitados.

password : Esta es la contraseña del usuario especificado.

Ejemplo completo

package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Videogames {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try {
Connection connection = DriverManager.getConnection(url, user,
password);
System.out.println("Conexión exitosa!");
} catch (SQLException e) {
e.printStackTrace();
}
}
}

Crear y Ejecutar Consultas


Una vez realizada la conexión, se pueden crear y ejecutar consultas SQL. Aquí hay un ejemplo
de cómo crear una tabla .

![02](C:\Breakline\Manuales\java\news\02.png)package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Videogames {


public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try (Connection connection = DriverManager.getConnection(url, user,


password);
Statement statement = connection.createStatement()) {

// Crear tabla
String createTableSQL = "CREATE TABLE IF NOT EXISTS games (" +
"id INT PRIMARY KEY AUTO_INCREMENT, " +
"name VARCHAR(50))";
statement.execute(createTableSQL);

System.out.println("Tabla creada !");

} catch (SQLException e) {
e.printStackTrace();
}
}
}
Insertar datos

package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Videogames {


public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try (Connection connection = DriverManager.getConnection(url, user,


password);
Statement statement = connection.createStatement()) {

// Crear tabla
String insertDataSQL = "INSERT INTO games (name) VALUES " +
"('The Legend of Zelda: Breath of the Wild'), " +
"('Super Mario Odyssey')";
statement.executeUpdate(insertDataSQL);
System.out.println("Juegos registrados");

} catch (SQLException e) {
e.printStackTrace();
}
}
}

Consultar información

package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.MessageFormat;

public class Videogames {


public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try (Connection connection = DriverManager.getConnection(url, user,


password);
Statement statement = connection.createStatement()) {

// Consultar datos
String query = "SELECT id,name FROM games";
ResultSet resultSet = statement.executeQuery(query);

// Procesar resultados
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println(MessageFormat.format("Id juego {0} -
Nombre {1}",id,name));
}

} catch (SQLException e) {
e.printStackTrace();
}
}
}

Actualizar Informacion

![03](C:\Breakline\Manuales\java\news\03.png)package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Videogames {


public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try (Connection connection = DriverManager.getConnection(url, user,


password);
Statement statement = connection.createStatement()) {

// Operación UPDATE
String updateSQL = "UPDATE juegos.games SET name = 'The Legend of
Zelda: Breath of the Wild - Updated' WHERE id = 1";
int rowsUpdated = statement.executeUpdate(updateSQL);
System.out.println("Número de filas actualizadas: " +
rowsUpdated);

} catch (SQLException e) {
e.printStackTrace();
}
}
}

Eliminar registros

package com.videogames;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Videogames {


public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/juegos";
String user = "root";
String password = "123456";

try (Connection connection = DriverManager.getConnection(url, user,


password);
Statement statement = connection.createStatement()) {

// Operación DELETE
String deleteSQL = "DELETE FROM games WHERE id = 1";
int rowsDeleted = statement.executeUpdate(deleteSQL);
System.out.println("Número de filas eliminadas: " + rowsDeleted);

} catch (SQLException e) {
e.printStackTrace();
}
}
}

GamesCRUD/

├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── controller/
│ │ │ │ └── GameController.java
│ │ │ │
│ │ │ ├── model/
│ │ │ │ ├── Game.java
│ │ │ │ └── GameDAO.java
│ │ │ │
│ │ │ └── view/
│ │ │ └── GameView.java
│ │ │
│ │ └── resources/
│ │ └── db.properties
│ │
│ └── test/
│ └── java/
│ └── controller/
│ └── GameControllerTest.java

├── .gitignore
├── pom.xml (o build.gradle)
└── README.md

Código proyecto
https://github.com/trainingLeader/videogames.git

Game.java

package com.videogames.model;

public class Game {


private int id;
private String name;
public Game() {
}
public Game(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

GameDao.java

package com.videogames.model;
/*
Las importaciones incluyen las clases necesarias para manejar conexiones de
base de datos (Connection, DriverManager), ejecutar consultas SQL
(PreparedStatement, Statement, ResultSet), manejar excepciones SQL
(SQLException), y manejar propiedades (Properties).
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/*
Clase GameDao: Define la clase que se encargará de las operaciones
sobre la base de datos.
Atributo connection: Este atributo almacenará la conexión activa a la
base de datos.
Propiedades de la Base de Datos:

Se crea un objeto Properties para cargar la configuración de la base


de datos desde un archivo db.properties ubicado
en el classpath.
props.load(...) carga las propiedades desde el archivo.
Conexión a la Base de Datos:
String url = props.getProperty("url"): Obtiene la URL de la base de
datos.
String user = props.getProperty("user"): Obtiene el nombre de usuario
para la base de datos.
String password = props.getProperty("password"): Obtiene la
contraseña para la base de datos.
connection = DriverManager.getConnection(url, user, password):
Establece la conexión utilizando DriverManager.
*/
public class GameDao {
private Connection connection;

public GameDao() {
try {
Properties props = new Properties();

props.load(getClass().getClassLoader().getResourceAsStream("db.properties"))
;
String url = props.getProperty("url");
String user = props.getProperty("user");
String password = props.getProperty("password");
connection = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
Consulta SQL:

String query = "INSERT INTO games (name) VALUES (?)": Define una
consulta SQL parametrizada para insertar un nuevo
juego.
Preparar la Consulta:
PreparedStatement ps = connection.prepareStatement(query): Crea un
PreparedStatement a partir de la consulta SQL. El
uso de PreparedStatement evita inyecciones SQL y permite manejar
parámetros de manera segura.

Asignar Parámetros:
ps.setString(1, game.getName()): Establece el valor del primer
parámetro (nombre del juego).
Ejecutar la Consulta:
ps.executeUpdate(): Ejecuta la consulta de inserción en la base de
datos.
*/
public void addGame(Game game) throws SQLException {
String query = "INSERT INTO games (name) VALUES (?)";
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, game.getName());
ps.executeUpdate();
}
/*
Crear una Lista de Juegos:

List<Game> games = new ArrayList<>(): Crea una lista para almacenar


los objetos Game.
Consulta SQL:

String query = "SELECT * FROM games": Define una consulta SQL para
seleccionar todos los juegos.
Crear un Statement y Ejecutar la Consulta:

Statement st = connection.createStatement(): Crea un objeto


Statement.
ResultSet rs = st.executeQuery(query): Ejecuta la consulta y obtiene
un ResultSet con los resultados.
Iterar sobre los Resultados:

while (rs.next()): Itera sobre cada fila en el ResultSet.


Game game = new Game(rs.getInt("id"), rs.getString("name")): Crea un
objeto Game para cada fila.
games.add(game): Agrega cada objeto Game a la lista.
Devolver la Lista:
return games: Devuelve la lista de juegos.
*/
public List<Game> getAllGames() throws SQLException {
List<Game> games = new ArrayList<>();
String query = "SELECT * FROM games";
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(query);
while (rs.next()) {
Game game = new Game(rs.getInt("id"), rs.getString("name"));
games.add(game);
}
return games;
}
/*
Consulta SQL:

String query = "UPDATE games SET name = ? WHERE id = ?": Define una
consulta SQL parametrizada para actualizar un
juego.
Preparar la Consulta:

PreparedStatement ps = connection.prepareStatement(query): Crea un


PreparedStatement.
Asignar Parámetros:

ps.setString(1, game.getName()): Establece el valor del nombre del


juego.
ps.setInt(2, game.getId()): Establece el valor del ID del juego.
Ejecutar la Consulta:

ps.executeUpdate(): Ejecuta la consulta de actualización.


*/
public void updateGame(Game game) throws SQLException {
String query = "UPDATE games SET name = ? WHERE id = ?";
PreparedStatement ps = connection.prepareStatement(query);
ps.setString(1, game.getName());
ps.setInt(2, game.getId());
ps.executeUpdate();
}
/*
Consulta SQL:

String query = "DELETE FROM games WHERE id = ?": Define una consulta
SQL parametrizada para eliminar un juego.
Preparar la Consulta:

PreparedStatement ps = connection.prepareStatement(query): Crea un


PreparedStatement.
Asignar Parámetros:

ps.setInt(1, id): Establece el valor del ID del juego.


Ejecutar la Consulta:

ps.executeUpdate(): Ejecuta la consulta de eliminación.


*/
public void deleteGame(int id) throws SQLException {
String query = "DELETE FROM games WHERE id = ?";
PreparedStatement ps = connection.prepareStatement(query);
ps.setInt(1, id);
ps.executeUpdate();
}
}

GameController.java

package com.videogames.controller;

import java.sql.SQLException;
import java.util.List;

import com.videogames.model.Game;
import com.videogames.model.GameDao;
import com.videogames.view.GameView;

public class GameController {


private GameView view;
private GameDao dao;

public GameController(GameView view, GameDao dao) {


this.view = view;
this.dao = dao;
}

public void start() {


while (true) {
int choice = view.showMenu();
try {
switch (choice) {
case 1:
addGame();
break;
case 2:
listGames();
break;
case 3:
updateGame();
break;
case 4:
deleteGame();
break;
case 5:
System.exit(0);
break;
default:
view.showMessage("Opción no válida.");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private void addGame() throws SQLException {
Game game = view.getGameDetails();
dao.addGame(game);
view.showMessage("Juego añadido exitosamente.");
}

private void listGames() throws SQLException {


List<Game> games = dao.getAllGames();
view.showGames(games);
}

private void updateGame() throws SQLException {


int id = view.getGameId();
Game game = view.getGameDetails();
game.setId(id);
dao.updateGame(game);
view.showMessage("Juego actualizado exitosamente.");
}

private void deleteGame() throws SQLException {


int id = view.getGameId();
dao.deleteGame(id);
view.showMessage("Juego eliminado exitosamente.");
}
}

GameView.java

package com.videogames.view;

import java.io.IOException;
import java.util.List;
import java.util.Scanner;

import com.videogames.model.Game;

public class GameView {


private Scanner scanner;

public GameView() {
scanner = new Scanner(System.in);
}
public int showMenu() {
//clearConsole();
System.out.println("1. Añadir juego");
System.out.println("2. Listar juegos");
System.out.println("3. Actualizar juego");
System.out.println("4. Eliminar juego");
System.out.println("5. Salir");
System.out.print("Selecciona una opción: ");
return scanner.nextInt();
}
public Game getGameDetails() {
scanner.nextLine();
System.out.println("Nombre del juego: ");
String name = scanner.nextLine();
return new Game(0, name);
}
public int getGameId() {
System.out.print("ID del juego: ");
return scanner.nextInt();
}
public void showGames(List<Game> games) {
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
int pageSize = 3;
int totalGames = games.size();
int totalPages = (int) Math.ceil((double) totalGames / pageSize);
String leftAlignFormat = "| %-4d | %-40s |%n";

for (int page = 1; page <= totalPages; page++) {


System.out.format("+------+--------------------------------------
----+%n");
System.out.format("| ID | Name
|%n");
System.out.format("+------+--------------------------------------
----+%n");

int start = (page - 1) * pageSize;


int end = Math.min(start + pageSize, totalGames);
for (int i = start; i < end; i++) {
Game game = games.get(i);
System.out.format(leftAlignFormat, game.getId(),
game.getName());
}

System.out.format("+------+--------------------------------------
----+%n");
System.out.println("Página " + page + " de " + totalPages);

if (page <= totalPages) {


System.out.println("Presiona Enter para mostrar la siguiente
página...");
try {

System.in.read();

} catch (IOException e) {
e.printStackTrace();
}
scanner.nextLine();
clearConsole();
}
}
}
public void showMessage(String message) {
System.out.println(message);
}
public static void clearConsole() {
try {
if (System.getProperty("os.name").contains("Windows")) {
new ProcessBuilder("cmd", "/c",
"cls").inheritIO().start().waitFor();
} else {
new ProcessBuilder("clear").inheritIO().start().waitFor();
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
}

db.properties

url=jdbc:mysql://localhost:3306/juegos
user=root
password=123456

Arquitectura de software
Definiciones
“La Arquitectura de Software se refiere a las estructuras de un sistema, compuestas de
elementos con propiedades visibles de forma externa y las relaciones que existen entre ellos.

— Software Engineering Institute (SEI)

“El conjunto de estructuras necesarias para razonar sobre el sistema, que comprende
elementos de software, relaciones entre ellos, y las propiedades de ambos. “
— Documenting Software Architectures: Views and Beyond (2nd
Edition), Clements et al, AddisonWesley, 2010

“La arquitectura de software de un programa o sistema informático es la estructura o


estructuras del sistema, que comprenden elementos de software, las propiedades visibles
externamente de esos elementos y las
relaciones entre ellos. “
— Software Architecture in Practice (2nd edition), Bass, Clements, Kazman; AddisonWesley
2003

“La arquitectura se define como la organización fundamental de un sistema, encarnada en


sus componentes, sus relaciones entre sí y con el entorno, y los principios que rigen su
diseño y evolución “
— ANSI/IEEE Std 1471-2000, Recommended Practice for Architectural Description of
SoftwareIntensive Systems

Arquitectura de software La arquitectura de software es el diseño de más alto nivel de


la estructura de un sistema, el cual consiste en un conjunto de patrones y
abstracciones que proporcionan un marco claro para la implementación del sistema.
Modelo Hexagonal
https://youtu.be/VLhdDYaW-uI?si=sI4B_Djx_TP1L-Am

El modelo hexagonal (también conocido como arquitectura de puertos y adaptadores) es un


patrón de arquitectura de software que separa el núcleo de la lógica de negocio (dominio) de
los detalles técnicos como las interfaces de usuario, bases de datos, sistemas de mensajería,
etc. Esto permite que la lógica de negocio sea independiente de los detalles de
implementación, facilitando el mantenimiento y la evolución del software. (https://youtu.be/e
NFAJbWCSww?si=oCiU5SwJBGErQxOr)

Estructura del Proyecto


1. domain: Contiene las entidades y servicios del núcleo de negocio.

2. application: Contiene los casos de uso.

3. infrastructure: Contiene los adaptadores para interactuar con tecnologías externas


(por ejemplo, persistencia, controladores web, etc.).

4. adapter: Contiene las implementaciones concretas de los puertos definidos en el


dominio y la aplicación.

my-hexagonal-console-app/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── adapter/
│ │ │ │ ├── in/
│ │ │ │ │ └── console/
│ │ │ │ │ └── ConsoleAdapter.java
│ │ │ │ └── out/
│ │ │ │ └── persistence/
│ │ │ │ └── MySQLUserRepository.java
│ │ │ ├── application/
│ │ │ │ └── usecase/
│ │ │ │ └── CreateUserUseCase.java
│ │ │ ├── domain/
│ │ │ │ └── User.java
│ │ │ ├── infrastructure/
│ │ │ │ ├── config/
│ │ │ │ │ └── DatabaseConfig.java
│ │ │ │ └── persistence/
│ │ │ │ └── UserRepository.java
│ │ │ └── main/
│ │ │ └── Main.java
│ └── test/
└── pom.xml
Dominio

User.java

package domain;

public class User {


private Long id;
private String name;
private String email;

// Getters and Setters


public Long getId() {
return id;
}

public void setId(Long id) {


this.id = id;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public String getEmail() {


return email;
}

public void setEmail(String email) {


this.email = email;
}
}

User service

package domain;

public interface UserService {


void createUser(User user);
User findUserById(Long id);
}

Aplicación

CreateUserUseCase.java

package application.usecase;

import domain.User;
import domain.UserService;

public class CreateUserUseCase {


private final UserService userService;

public CreateUserUseCase(UserService userService) {


this.userService = userService;
}

public void execute(User user) {


userService.createUser(user);
}
}

Infraestructura

DatabaseConfig.java

package infrastructure.config;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConfig {


private static final String URL = "jdbc:mysql://localhost:3306/usuarios";
private static final String USER = "root";
private static final String PASSWORD = "123456";

public static Connection getConnection() throws SQLException {


return DriverManager.getConnection(URL, USER, PASSWORD);
}
}

Adaptadores

ConsoleAdapter.java

package adapter.in.console;

import application.usecase.CreateUserUseCase;
import domain.User;

import java.util.Scanner;

public class ConsoleAdapter {


private final CreateUserUseCase createUserUseCase;

public ConsoleAdapter(CreateUserUseCase createUserUseCase) {


this.createUserUseCase = createUserUseCase;
}

public void start() {


Scanner scanner = new Scanner(System.in);
System.out.println("Enter user name: ");
String name = scanner.nextLine();

System.out.println("Enter user email: ");


String email = scanner.nextLine();

User user = new User();


user.setName(name);
user.setEmail(email);

createUserUseCase.execute(user);

System.out.println("User created successfully!");


}
}

MySQLUserRepository.java

package adapter.out.persistence;

import domain.User;
import domain.UserService;
import infrastructure.config.DatabaseConfig;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MySQLUserRepository implements UserService {

@Override
public void createUser(User user) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";

try (Connection connection = DatabaseConfig.getConnection();


PreparedStatement statement = connection.prepareStatement(sql,
PreparedStatement.RETURN_GENERATED_KEYS)) {

statement.setString(1, user.getName());
statement.setString(2, user.getEmail());
statement.executeUpdate();

try (ResultSet generatedKeys = statement.getGeneratedKeys()) {


if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
}
}

} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public User findUserById(Long id) {
String sql = "SELECT id, name, email FROM users WHERE id = ?";
User user = null;

try (Connection connection = DatabaseConfig.getConnection();


PreparedStatement statement = connection.prepareStatement(sql))
{

statement.setLong(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
user = new User();
user.setId(resultSet.getLong("id"));
user.setName(resultSet.getString("name"));
user.setEmail(resultSet.getString("email"));
}
}

} catch (SQLException e) {
e.printStackTrace();
}

return user;
}
}

Main

package main;

import adapter.in.console.ConsoleAdapter;
import adapter.out.persistence.MySQLUserRepository;
import application.usecase.CreateUserUseCase;
import domain.UserService;

public class Main {


public static void main(String[] args) {
UserService userService = new MySQLUserRepository();
CreateUserUseCase createUserUseCase = new
CreateUserUseCase(userService);
ConsoleAdapter consoleAdapter = new
ConsoleAdapter(createUserUseCase);

consoleAdapter.start();
}
}
Expresiones Lambda
Las expresiones lambda en Java, introducidas en la versión 8 del lenguaje, son una característica
que permite tratar las funciones como objetos. Proveen una sintaxis más concisa y flexible para la
implementación de interfaces funcionales, que son interfaces con un único método abstracto.

Características de las Expresiones Lambda


Sintaxis Concisa: Permiten escribir el código de forma más concisa, eliminando la necesidad
de clases anónimas.

Interfaces Funcionales: Trabajan principalmente con interfaces funcionales, como


Runnable , Callable , Comparator , y las interfaces del paquete java.util.function .

Legibilidad: Hacen el código más legible y más fácil de mantener.

Sintaxis de una Expresión Lambda


La sintaxis básica de una expresión lambda es:

(parameters) -> expression


o
(parameters) -> { statements; }

Ejemplos de Expresiones Lambda


Sin Parámetros:

() -> System.out.println("Hola, Mundo!");

Con un Parámetro:

(x) -> x * x

Con Múltiples Parámetros:

(a, b) -> a + b

Bloque de Código:

(int x, int y) -> {


int sum = x + y;
return sum;
}
Uso de Expresiones Lambda
Iterar sobre una colección:

package com.breaklinestudio.projectintro;

import java.util.Arrays;
import java.util.List;

public class Main {


public static void main(String[] args) {
List<String> lista = Arrays.asList("uno", "dos", "tres");
lista.forEach(s -> System.out.println(s));
}
}

Explicación del Código


1. Paquete y Importaciones: El código comienza con la declaración del paquete y las
importaciones necesarias.

2. Clase Principal: La clase Main contiene el método main , que es el punto de entrada del
programa.

3. Crear una Lista: En el método main , se crea una lista de cadenas lista que contiene los
elementos "uno", "dos" y "tres".

4. Iteración con Lambda: Utilizando el método forEach y una expresión lambda, el programa
itera sobre cada elemento de la lista e imprime cada elemento en la consola.

Ordenar Usando Comparator con Expresión Lambda


Comparator porEdad = (p1, p2) -> Integer.compare(p1.getEdad(), p2.getEdad());

Interfaz Funcional Comparator :

Comparator es una interfaz funcional que tiene un único método abstracto llamado
compare .

Su firma es int compare(T o1, T o2) , donde T es el tipo de los objetos a comparar (en
este caso, Persona ).

public class Persona {


private String nombre;
private int edad;

public Persona(String nombre, int edad) {


this.nombre = nombre;
this.edad = edad;
}

public String getNombre() {


return nombre;
}

public int getEdad() {


return edad;
}

@Override
public String toString() {
return nombre + " - " + edad;
}
}

package com.breaklinestudio.projectintro;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {


public static void main(String[] args) {
List<Persona> personas = new ArrayList<>();
personas.add(new Persona("Carlos", 25));
personas.add(new Persona("Ana", 23));
personas.add(new Persona("Jose", 30));
personas.add(new Persona("Maria", 20));
// Usar un Comparator con expresión lambda para ordenar por edad
Comparator<Persona> porEdad = (p1, p2) -> Integer.compare(p1.getEdad(),
p2.getEdad());

Collections.sort(personas, porEdad);

// Mostrar la lista ordenada


personas.forEach(System.out::println);
}
}

Parámetros de la Lambda:

(p1, p2) son los dos parámetros de la expresión lambda. Representan los dos objetos
Persona que queremos comparar.

p1 y p2 son dos variables temporales que se usaran para realizar la comparación.

Cuerpo de la Lambda:

Integer.compare(p1.getEdad(), p2.getEdad()) es el cuerpo de la lambda, que realiza la


comparación entre las edades de p1 y p2 .

p1.getEdad() obtiene la edad de la primera persona ( p1 ).

p2.getEdad() obtiene la edad de la segunda persona ( p2 ).

Integer.compare(int x, int y)

es un método estático de la clase

Integer
que compara dos valores

int

y devuelve:

Un valor negativo si x es menor que y .

Cero si x es igual a y .

Un valor positivo si x es mayor que y .

Consumer
En Java, Consumer es una interfaz funcional introducida en Java 8 como parte del paquete
java.util.function . La interfaz Consumer representa una operación que toma un solo
argumento y no devuelve ningún resultado. Se utiliza principalmente para pasar operaciones que
se aplicarán a cada elemento de una colección de elementos, como con el método forEach de las
colecciones.

Características de Consumer
Interfaz Funcional: Consumer es una interfaz funcional, lo que significa que tiene un solo
método abstracto.

Método Abstracto: El único método abstracto en Consumer es accept(T t) , que toma un


argumento de tipo T y devuelve void .

Uso de Consumer con Expresiones Lambda


Las expresiones lambda son una forma conveniente de implementar la interfaz Consumer . Vamos
a ver un ejemplo para ilustrar su uso.

Ejemplo: Uso de Consumer con Expresiones Lambda


Supongamos que tenemos una lista de Estudiante y queremos imprimir el nombre de cada
estudiante usando Consumer con una expresión lambda.

package com.breaklinestudio.projectintro;

public class Estudiante {


private String nombre;
private double nota;

public Estudiante(String nombre, double nota) {


this.nombre = nombre;
this.nota = nota;
}

public String getNombre() {


return nombre;
}

public double getNota() {


return nota;
}

@Override
public String toString() {
return nombre + " - " + nota;
}
}

package com.breaklinestudio.projectintro;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class Main {


public static void main(String[] args) {
List<Estudiante> estudiantes = new ArrayList<>();
estudiantes.add(new Estudiante("Carlos", 85.5));
estudiantes.add(new Estudiante("Ana", 92.0));
estudiantes.add(new Estudiante("Jose", 78.3));
estudiantes.add(new Estudiante("Maria", 88.9));

// Usar una expresión lambda con Consumer para imprimir el nombre de cada
estudiante
Consumer<Estudiante> imprimirNombre = estudiante ->
System.out.println(estudiante.getNombre());

// Aplicar el Consumer a cada elemento de la lista


estudiantes.forEach(imprimirNombre);
}
}

BiConsumer
BiConsumer es una interfaz funcional en Java que se introdujo en Java 8 como parte del paquete
java.util.function . Al igual que Consumer , BiConsumer representa una operación que acepta
dos argumentos y no devuelve ningún resultado. Se utiliza principalmente cuando se desea
realizar una operación en un par de objetos.

Características de BiConsumer
Interfaz Funcional: BiConsumer es una interfaz funcional, lo que significa que tiene un
único método abstracto.

Método Abstracto: El método abstracto de BiConsumer es accept(T t, U u) , que toma


dos argumentos de tipo T y U y devuelve void .
Sintaxis de BiConsumer
La sintaxis básica de una expresión lambda que implementa un BiConsumer es:

(T t, U u) -> { // cuerpo de la lambda }

Ejemplo de Uso de BiConsumer con Expresiones Lambda


Supongamos que tenemos una lista de entradas (pares clave-valor) y queremos procesarlas
usando BiConsumer .

Ejemplo: Procesar Pares Clave-Valor

A continuación, un ejemplo de cómo usar BiConsumer para procesar un Map de claves y valores.

package com.breaklinestudio.projectintro;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class Main {


public static void main(String[] args) {
// Crear un Map de claves y valores
Map<String, Integer> items = new HashMap<>();
items.put("Apple", 10);
items.put("Banana", 20);
items.put("Orange", 30);
items.put("Mango", 25);
items.put("Grapes", 50);

// Definir un BiConsumer para procesar las entradas del Map


BiConsumer<String, Integer> procesarEntrada = (clave, valor) ->
System.out.println("Fruta: " + clave + ", Cantidad: " + valor);

// Aplicar el BiConsumer a cada entrada del Map


items.forEach(procesarEntrada);
}
}

Supplier
En Java, Supplier es una interfaz funcional que se introdujo en Java 8 como parte del paquete
java.util.function . Supplier representa una función que no toma argumentos y proporciona
un resultado. Se usa principalmente en situaciones donde necesitas generar o proporcionar
valores sin necesidad de parámetros de entrada.
Características de Supplier
Interfaz Funcional: Supplier es una interfaz funcional, lo que significa que tiene un único
método abstracto.

Método Abstracto: El único método abstracto en Supplier es get() , que no toma


argumentos y devuelve un valor de tipo T .

Sintaxis de Supplier
La sintaxis básica de una expresión lambda que implementa un Supplier es:

() -> expresión

Ejemplo: Generar un Valor Aleatorio

Supongamos que queremos generar un número aleatorio utilizando Supplier .

package com.breaklinestudio.projectintro;

import java.util.Random;

import java.util.function.Supplier;

public class Main {


public static void main(String[] args) {
// Crear un Supplier que proporciona un número aleatorio
Supplier<Integer> generarNumeroAleatorio = () -> {
Random random = new Random();
return random.nextInt(100); // Número aleatorio entre 0 y 99
};

// Usar el Supplier para obtener un número aleatorio


Integer numeroAleatorio = generarNumeroAleatorio.get();
System.out.println("Número aleatorio: " + numeroAleatorio);

// Obtener otro número aleatorio


Integer otroNumeroAleatorio = generarNumeroAleatorio.get();
System.out.println("Otro número aleatorio: " + otroNumeroAleatorio);
}
}

Interfaz Supplier : Representa una función que no toma argumentos y proporciona un


resultado.

Método get : No toma argumentos y devuelve un valor.

Expresiones Lambda: Se pueden usar para implementar de manera concisa la interfaz


Supplier .
Ejercicio:
usar Supplier para generar instancias aleatorias de una clase Persona , haciendo el código más
flexible y reutilizable.

package com.breaklinestudio.projectintro;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.function.Supplier;

public class Main {


public static void main(String[] args) {
// Crear un array de nombres posibles
String[] nombres = {"Carlos", "Ana", "Jose", "Maria", "Luis"};

// Crear un Set para rastrear nombres ya usados


Set<String> nombresUsados = new HashSet<>();

// Crear un Supplier que proporciona instancias de Persona sin nombres


repetidos
Supplier<Persona> generarPersonaAleatoria = () -> {
Random random = new Random();
String nombreAleatorio = null;

// Encontrar un nombre que no haya sido usado


while (true) {
nombreAleatorio = nombres[random.nextInt(nombres.length)];
if (!nombresUsados.contains(nombreAleatorio)) {
nombresUsados.add(nombreAleatorio);
break;
}
}

int edadAleatoria = 18 + random.nextInt(43); // Edad entre 18 y 60


return new Persona(nombreAleatorio, edadAleatoria);
};
// Usar el Supplier para obtener instancias de Persona
for (int i = 0; i < nombres.length; i++) {
Persona persona = generarPersonaAleatoria.get();
System.out.println(persona);
}
}
}

Explicación del Código


1. Definición de la Clase Persona :

La clase Persona tiene dos atributos: nombre y edad .

Incluye los métodos getNombre , getEdad y toString .


2. Crear un Array de Nombres Posibles:

Definimos un array de nombres posibles para las instancias de Persona .

3. Crear un Set para Rastrear Nombres Usados:

Usamos un Set<String> para mantener un registro de los nombres que ya se han


utilizado. Los Set no permiten duplicados, por lo que es ideal para este propósito.

4. Definir un Supplier Usando una Expresión Lambda:

Definimos un Supplier utilizando una expresión lambda para generar instancias de


Persona con nombres y edades aleatorias, asegurándonos de que los nombres no se
repitan.

5. Usar el Supplier para Obtener Instancias de Persona :

Usamos el método get() del Supplier para obtener varias instancias de Persona y
las imprimimos.

Predícate
En Java, Predicate es una interfaz funcional que se introdujo en Java 8 como parte del paquete
java.util.function . Un Predicate representa una función que toma un solo argumento y
devuelve un valor booleano. Se usa comúnmente para pruebas o evaluaciones de condiciones
sobre datos.

Características de Predicate
Interfaz Funcional: Predicate es una interfaz funcional, lo que significa que tiene un único
método abstracto.

Método Abstracto: El método abstracto en Predicate es test(T t) , que toma un


argumento de tipo T y devuelve un valor booleano.

Métodos Comunes en Predicate


Además del método abstracto test , la interfaz Predicate proporciona métodos
predeterminados para combinar predicados:

and: Combina este predicado con otro predicado usando una operación lógica AND.

or: Combina este predicado con otro predicado usando una operación lógica OR.

negate: Devuelve un predicado que representa la negación de este predicado.

isEqual: Devuelve un predicado que prueba si dos argumentos son iguales.

Sintaxis de una Expresión Lambda que Implementa


Predicate
La sintaxis básica de una expresión lambda que implementa un Predicate es:

(parameter) -> boolean_expression


Ejemplos de Uso
A continuación se presentan varios ejemplos que muestran cómo usar Predicate con
expresiones lambda.

1. Ejemplo Básico con Predicate


Definición: Predicate que verifica si un número es par.

package com.breaklinestudio.projectintro;

import java.util.function.Predicate;

public class Main {


public static void main(String[] args) {
Predicate<Integer> esPar = n -> n % 2 == 0;

System.out.println("4 es par: " + esPar.test(4));


System.out.println("7 es par: " + esPar.test(7));
}
}

Explicación del Código


1. Definir un Predicate Usando una Expresión Lambda:

Predicate<Integer> esPar = n -> n % 2 == 0;

(n) es el parámetro de la lambda que representa el número a probar.

n % 2 == 0 es la expresión que devuelve true si n es par y false en caso contrario.

2. Usar el Método test :

esPar.test(4) evalúa si 4 es par y devuelve true .

esPar.test(7) evalúa si 7 es par y devuelve false .

2. Ejemplo con Listas y Predicate


Definición: Filtrar una lista de números para encontrar solo los pares.

package com.breaklinestudio.projectintro;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {


public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Predicate<Integer> esPar = n -> n % 2 == 0;

List<Integer> numerosPares = numeros.stream()


.filter(esPar)
.collect(Collectors.toList());
System.out.println("Números pares: " + numerosPares);
}
}

Explicación del Código


1. Definir un Predicate Usando una Expresión Lambda:

Predicate<Integer> esPar = n -> n % 2 == 0;

2. Filtrar la Lista Usando el Predicate :

numeros.stream().filter(esPar).collect(Collectors.toList());

stream() convierte la lista en un stream. En Java, un Stream es una secuencia de


elementos que permite realizar operaciones sobre los datos de manera declarativa y
funcional. Los Streams se introdujeron en Java 8 como parte del paquete
java.util.stream y son una herramienta poderosa para procesar colecciones de
datos.

Características de los Streams


1. Declarativos: Permiten escribir código más legible y declarativo, centrándose en el
"qué" hacer en lugar del "cómo" hacerlo.

2. Lazy Evaluation (Evaluación Perezosa): Las operaciones intermedias en un


Stream no se ejecutan hasta que se invoca una operación terminal.

3. Pipeline: Permiten encadenar múltiples operaciones en un pipeline de


procesamiento.

4. Inmutables: Los Streams no modifican la colección original sino que producen un


nuevo Stream con los resultados.

5. Paralelismo: Facilitan el procesamiento paralelo de datos de manera sencilla.

filter(esPar) aplica el Predicate para filtrar solo los números pares.

collect(Collectors.toList()) recoge los resultados en una nueva lista.

3. Combinación de Predicados

Definición: Combinar varios predicados para verificar condiciones complejas.

package com.breaklinestudio.projectintro;

import java.util.function.Predicate;

public class Main {


public static void main(String[] args) {
Predicate<String> empiezaConJ = s -> s.startsWith("J");
Predicate<String> longitudMayorA4 = s -> s.length() > 4;

Predicate<String> empiezaConJYLarga = empiezaConJ.and(longitudMayorA4);


System.out.println("Java empieza con J y es larga: " +
empiezaConJYLarga.test("Java"));
System.out.println("Julia empieza con J y es larga: " +
empiezaConJYLarga.test("Julia"));
System.out.println("Juan empieza con J y es larga: " +
empiezaConJYLarga.test("Juan"));

}
}

Explicación del Código


1. Definir Varios Predicate Usando Expresiones Lambda:

Predicate<String> empiezaConJ = s -> s.startsWith("J");

Predicate<String> longitudMayorA4 = s -> s.length() > 4;

2. Combinar Predicados Usando and :

Predicate<String> empiezaConJYLarga = empiezaConJ.and(longitudMayorA4);

3. Usar el Método test con el Predicado Combinado:

empiezaConJYLarga.test("Java") devuelve false porque "Java" tiene 4 caracteres.

empiezaConJYLarga.test("Julia") devuelve true porque "Julia" empieza con "J" y


tiene más de 4 caracteres.

empiezaConJYLarga.test("Juan") devuelve false porque "Juan" tiene 4 caracteres

Ejemplo Completo con la Clase Persona


Supongamos que tenemos una clase Persona y queremos usar Predicate para evaluar ciertas
condiciones sobre una lista de personas.

package com.breaklinestudio.projectintro;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Main {


public static void main(String[] args) {
List<Persona> personas = new ArrayList<>();
personas.add(new Persona("Carlos", 25));
personas.add(new Persona("Ana", 23));
personas.add(new Persona("Jose", 30));
personas.add(new Persona("Maria", 15));

// Predicate para verificar si una persona es mayor de edad


Predicate<Persona> esMayorDeEdad = p -> p.getEdad() >= 18;

// Predicate para verificar si una persona se llama "Ana"


Predicate<Persona> seLlamaAna = p -> p.getNombre().equals("Ana");
// Filtrar personas mayores de edad
List<Persona> mayoresDeEdad = personas.stream()
.filter(esMayorDeEdad)
.collect(Collectors.toList());

System.out.println("Mayores de edad: " + mayoresDeEdad);

// Filtrar personas que se llaman "Ana"


List<Persona> personasQueSeLlamanAna = personas.stream()
.filter(seLlamaAna)

.collect(Collectors.toList());

System.out.println("Personas que se llaman Ana: " +


personasQueSeLlamanAna);
}
}

Stream
En Java, un Stream es una secuencia de elementos que permite realizar operaciones sobre los
datos de manera declarativa y funcional. Los Streams se introdujeron en Java 8 como parte del
paquete java.util.stream y son una herramienta poderosa para procesar colecciones de datos.

Características de los Streams


1. Declarativos: Permiten escribir código más legible y declarativo, centrándose en el "qué"
hacer en lugar del "cómo" hacerlo.

2. Lazy Evaluation (Evaluación Perezosa): Las operaciones intermedias en un Stream no se


ejecutan hasta que se invoca una operación terminal.

3. Pipeline: Permiten encadenar múltiples operaciones en un pipeline de procesamiento.

4. Inmutables: Los Streams no modifican la colección original sino que producen un nuevo
Stream con los resultados.

5. Paralelismo: Facilitan el procesamiento paralelo de datos de manera sencilla.

Componentes Principales de los Streams


1. Fuente (Source): La fuente de datos para el Stream, como una colección, un array, o una I/O
channel.

2. Operaciones Intermedias: Transforman un Stream en otro Stream. Son operaciones


perezosas y no ejecutan hasta que se invoca una operación terminal (e.g., filter , map ).

3. Operaciones Terminales: Producen un resultado o efecto secundario (e.g., forEach ,


collect , reduce ).

Ejemplo Básico de Uso de Streams


Supongamos que tenemos una lista de números y queremos realizar varias operaciones sobre
ella usando Streams.
package com.breaklinestudio.projectintro;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {


public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Crear un Stream, filtrar números pares y recolectar en una lista


List<Integer> pares = numeros.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());

System.out.println("Números pares: " + pares);

// Crear un Stream, mapear a sus cuadrados y recolectar en una lista


List<Integer> cuadrados = numeros.stream()
.map(n -> n * n)
.collect(Collectors.toList());

System.out.println("Cuadrados de los números: " + cuadrados);

// Crear un Stream, filtrar números mayores que 5, mapear a sus cuadrados


y recolectar en una lista
List<Integer> cuadradosMayoresQue5 = numeros.stream()
.filter(n -> n > 5)
.map(n -> n * n)

.collect(Collectors.toList());

System.out.println("Cuadrados de números mayores que 5: " +


cuadradosMayoresQue5);

}
}

Operaciones Comunes en Streams


1. filter
Filtra los elementos de un Stream según una condición.

List<String> nombres = Arrays.asList("Ana", "Carlos", "Beatriz", "David");


List<String> nombresConA = nombres.stream()
.filter(n -> n.contains("a"))
.collect(Collectors.toList());

System.out.println("Nombres con 'a': " + nombresConA);


2. map
Transforma cada elemento de un Stream.

List<Integer> numeros = Arrays.asList(1, 2, 3, 4);


List<Integer> dobles = numeros.stream()
.map(n -> n * 2)
.collect(Collectors.toList());

System.out.println("Dobles de los números: " + dobles);

3. collect
Recoge los elementos de un Stream en una colección.

List<Integer> lista = Stream.of(1, 2, 3, 4, 5)


.collect(Collectors.toList());

System.out.println("Lista: " + lista);

4. forEach
Aplica una acción a cada elemento del Stream.

Stream.of("Uno", "Dos", "Tres")


.forEach(System.out::println);

5. reduce
Reduce los elementos del Stream a un único valor.

package com.breaklinestudio.projectintro;

import java.util.stream.Stream;

public class Main {


public static void main(String[] args) {
int suma = Stream.of(1, 2, 3, 4, 5)
.reduce(0, Integer::sum);
System.out.println("Suma: " + suma);
}
}
Ejemplo Completo con la Clase Persona
Supongamos que tenemos una clase Persona y queremos realizar varias operaciones con
Streams.

package com.breaklinestudio.projectintro;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Main {


public static void main(String[] args) {
List<Persona> personas = new ArrayList<>();
personas.add(new Persona("Carlos", 25));
personas.add(new Persona("Ana", 23));
personas.add(new Persona("Jose", 30));
personas.add(new Persona("Maria", 20));

// Filtrar personas mayores de edad


List<Persona> mayoresDeEdad = personas.stream()
.filter(p -> p.getEdad() >= 18)
.collect(Collectors.toList());

System.out.println("Mayores de edad: " + mayoresDeEdad);

// Obtener los nombres de las personas


List<String> nombres = personas.stream()
.map(Persona::getNombre)
.collect(Collectors.toList());

System.out.println("Nombres: " + nombres);

// Calcular la suma de las edades


int sumaEdades = personas.stream()
.map(Persona::getEdad)
.reduce(0, Integer::sum);

System.out.println("Suma de las edades: " + sumaEdades);


}
}

Generar Ejecutable
Instalar en linux
Siga la siguiente guia https://www.digitalocean.com/community/tutorials/install-maven-linux-ubun
tu

Instalar maven windows


Acceder a la url https://maven.apache.org/

En el menu lateral seleccionar la opcion Donwload


En la lista de descargas seleccionar Binary zip archive

Descomprimir el archivo descargado

Copiar la carpeta en la unidad de disco C;/ o donde desee copiar la descarga. Para la guia se
copiara en c:

Crear las Variables de entorno. Para configurar las variable de entorno en el buscador de
aplicaciones escriba Variables de

entorno.
Seleccione la ruta donde copio la carpeta de maven. Para el caso de la guia C:\apache-maven.
En la ventana de variables de entorno haga clic en el boton

En la ventana de creacion de la variable de entorno ingrese los datos segun los datos
obtenidos en los pasos anteriores. Ver imagen.
En la seccion variables del sistema seleccione path y presione el boton editar.
En la ventana de edicion de las variables de path seleccione nuevo y escriba
%MAVEN_HOME%\bin y haga clic en el boton de aceptar para terminar.
Por ultimo para cerrar la ventana de configuración de variables de entorno haga clic en el
boton aceptar.

Probar configuracion de maven


1. Abra una terminal (cmd o powershell)

2. En el prompt escriba mvn -version

Configuración del proyecto en Visual Studio Code


Agregar la etiqueta

<packaging>jar</packaging>

Despues de la etiqueta 1.0-SNAPSHOT


En el archivo pom.xml del proyecto agregue el codigo inferior. Se recomienda pegar este codigo
despues de la etiqueta dependencies

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>

<mainClass>com.NombreProyecto.NombreClasePrincipal</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Ejemplo completo pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.ligabetplay</groupId>
<artifactId>ligabetplay</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<dependencies>

<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->


<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
</dependency>

</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.ligabetplay.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Abra la terminal de visual studio code o power shell. Debe estar ubicado en la carpeta del
proyecto, ingrese el siguiente comando :

mvn clean package

También podría gustarte