Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Jaime Salvador
Version v1.0.0
Tabla de contenidos
Lista de figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Lista de código. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. Genéricos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1. Búsqueda en un arreglo de elementos Integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Búsqueda en un arrego de elementos Persona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3. Búsqueda genérica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.1. Gestionar valores no encontrados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4. Encontrar el mínimo y máximo de un arreglo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5. Leer datos de un archivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.5.1. Instanciar un vector genérico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.5.2. Crear instancias de un tipo genérico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.5.3. Implementación completa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2. Interfaces funcionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1. Gradle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.2. Constructores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3. Creación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4. Operaciones de filtrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.4.1. first . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.4.2. last . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.4.3. take . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.4.4. takeLast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.4.5. skip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.4.6. skipLast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.4.7. filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.5. Operaciones condicionales y booleanas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.1. all. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.2. any . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.5.3. contains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.4. takeWhile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.5. skipWhile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1
Lista de figuras
Figura 1. Tipos de datos comparables
Figura 2. Algoritmo leer datos de un archivo de texto CSV
Figura 3. Interfaz RowParser
Figura 4. ArrayDataset
Lista de código
Listado 1. Búsqueda de valores enteros
Listado 2. Búsqueda de objetos tipo Persona
Listado 3. Búsqueda con Genéricos
Listado 4. Búsqueda con Genéricos y tipo de dato opcional
Listado 5. Máximo y mínimo de un arreglo
Listado 6. Lectura de un archivo de texto separado por comas (,)
Jaime Salvador M.
2 1. Genéricos
1. Genéricos
En esta sección se consideran los siguientes ejercicios:
class BuscarEnteros {
return null;
}
Escribir el método que permita buscar una Persona en base a su ID. Por ejemplo, si se tiene el
arreglo de personas:
[
[1, "nombre1", "dir1", 10],
[2, "nombre2", "dir2", 15],
[3, "nombre3", "dir3", 23],
[4, "nombre4", "dir4", 18],
[5, "nombre5", "dir5", 14]
]
buscar la persona con ID=3. El método debe retornar la Persona y el índice en el que se
encuentra: ([3, "nombre3", "dir3", 23], 2) el valor [3, "nombre3", "dir3", 23]
corresponde a la Persona con ID=3 y el valor 2 corresponde al índice dentro del vector.
class BuscarPersonas {
return null;
}
Jaime Salvador M.
4 1.2. Búsqueda en un arrego de elementos Persona
El caso más completo implica buscar una persona en base a una condición general representada
por Predicate<T>, para esto el método de búsqueda debe recibir el arreglo de personas así como
el predicado a aplicar, es decir:
Con estas variaciones, el método general para buscar personas en base a una condición arbitraria
es el siguiente:
import java.util.function.Predicate;
class BuscarPersonas {
return null;
}
• Las dos búsquedas necesitan clases para almacenar el valor retornado IntegerPos para la
búsqueda de valores enteros y PersonaPos para la búsqueda de personas.
• El algoritmo de iteración sobre los datos es el mismo, básicamente un for que itera sobre los
datos, el chequeo de una condición y el retorno del resultado.
El valor de retorno se lo puede representar como una clase genérica con dos parámetros:
return null;
}
El método de búsqueda puede ser generalizado para un arreglo de cualquier tipo (por ejemplo T) y
la condición se la puede generalizar utilizando un predicado que chequea elementos del vector, en
este caso Predicate<T>. De esta forma, el método genérico de búsqueda es el siguiente:
import java.util.function.Predicate;
return null;
}
Jaime Salvador M.
6 1.3. Búsqueda genérica
Utilizar el tipo de dato Optiona<T> como valor de retorno del método buscar:
return Optional.empty(); ❷
7
return Optional.empty();
}
if (optPersona.isPresent()) {
var data = optPersona.get();
Jaime Salvador M.
8 1.4. Encontrar el mínimo y máximo de un arreglo
De la descripción anterior, es necesario que los elementos del vector sean comparables (menor
que, mayor que). Los tipos de datos numéricos (tipos wrappers) son comparables, sin embargo
tipos de datos personalizados como la clase Persona no son comparables por defecto.
Si definimos el método static <T> Pair<T,T> minMax(T[] data), es necesario que el tipo T sea
un tipo comparables, esto es T es un/una Comparable.
[
[1, "nombre1", "dir1", 10],
[2, "nombre2", "dir2", 15],
[3, "nombre3", "dir3", 23],
[4, "nombre4", "dir4", 18],
[5, "nombre5", "dir5", 14]
]
Podemos buscar la persona que tiene la edad más baja (mínimo) y la persona que tiene la edad
más alta (máximo), en este caso el concepto de Comparar Personas se reduce a comparar las
edades; esto es: una persona es menor que otra (o mayor) si la edad es menor (o mayor).
Con la jerarquía anterior, la búsqueda del mínimo y máximo es posible siempre que el arreglo
contega objetos que implementen la interface Comparable (que sean comparables). Por lo tanto, el
tipo de dato T del método minMax debe extender/implementar la interface comparable:
for(int i=0;i<data.length;i++) {
if(data[i].compareTo(min)<0) {
min = data[i];
}
if(data[i].compareTo(max)>0) {
max= data[i];
}
}
return Pair.of(min,max);
}
150 ❶
5.1,3.5,1.4,0.2,Iris-setosa ❷
4.9,3.0,1.4,0.2,Iris-setosa
Jaime Salvador M.
10 1.5. Leer datos de un archivo
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
..
Para representar esta información se crea la clase IrisRow la cual contiene atributos asociados a
la información descrita anteriormente.
Jaime Salvador M.
12 1.5. Leer datos de un archivo
int index = 0;
for (int i = 0; i < size; i++) { ❹
// leer una línea del archivo
line = brd.readLine(); ❺
if (!line.isBlank()) {
//separar las palabras utilizando `,`
var tokens = line.split(","); ❻
ret[index] = item; ❽
index++;
}
}
return ret; ❾
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Las líneas del código marcadas con 1, 2, 4, 5, 6, 8 y 9 son generales y no dependen del tipo de
información contenida en el archivo. Por otro lado, las líneas del código marcadas con 3 y 7 son
particulares y dependen del tipo de información contenida en el archivo.
int index = 0;
for (int i = 0; i < size; i++) {
// leer una línea del archivo
line = brd.readLine();
if (!line.isBlank()) {
//separar las palabras utilizando `,`
var tokens = line.split(",");
ret[index] = item;
index++;
}
}
return ret;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
1. TIPO representa un dato genérico que puede ser de tipo IrisRow o cualquier otro tipo
dependiendo del archivo de datos (punto 1)
2. Es necesario instanciar un vector cuyos elementos son genéricos (punto 2)
3. Es necesario crear instancia del tipo genérico (punto 3)
Jaime Salvador M.
14 1.5. Leer datos de un archivo
Donde:
class DemoArrayGenerico {
static <T> T[] crearVector(Class<T> cls, int size) {
T[] arr = (T[] )Array.newInstance(cls, size); ❶
return arr;
}
Para todas las clases en Java, es posible determiar el tipo de dato utilizando la
sintaxis NombreClase.class, por ejemplo Integer.class, String.class,
IrisRow.class.
Utilizando lo indicado anteriormente, podemos rescribir el algoritmo de lectura del archivo dela
siguiente forma:
int index = 0;
for (int i = 0; i < size; i++) {
// leer una línea del archivo
line = brd.readLine();
if (!line.isBlank()) {
15
ret[index] = item;
index++;
}
}
return ret;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
En el método para leer un archivo, en la sección marcada con 3, es necesario realizar lo siguiente:
ret[index] = item;
Es posible crear instancias de tipo genérico utilizando la clase asociada al tipo (Integer.class,
String.class, etc):
class DemoCrearGenerico {
static <T> T crearGenerico(Class<T> cls) {
try {
T obj = cls.getConstructor() ❶
.newInstance();
return obj;
Jaime Salvador M.
16 1.5. Leer datos de un archivo
} catch (Exception e) {
throw new RuntimeException(e);
}
}
El código anterior permite crear instancias de tipos genéricos asumiendo que la clase tiene un
constructor por defecto (sin parámetros). Luego de crear la istancia, es necesario fijar los valores
de cada uno de los atributos. Es posible fijar los valores de los atributos de una clase utilizando
reflexión[1], sin embargo es una tarea más complicada que la creación de uns instancia.
En lugar de crear instancias de tipos genéricos, una solución más simple es abstraer la acción de
creación e inicialización de la instancia a través de una interface que la llamaremos RowParser<T>.
int index = 0;
17
if (!line.isBlank()) {
//separar las palabras utilizando `,`
var tokens = line.split(",");
T item = parser.parse(tokens); ❶
ret[index] = item;
index++;
}
}
return ret;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
int index = 0;
for (int i = 0; i < size; i++) {
// leer una línea del archivo
line = brd.readLine();
if (!line.isBlank()) {
//separar las palabras utilizando `,`
var tokens = line.split(",");
T item = parser.parse(tokens);
ret[index] = item;
index++;
}
}
Jaime Salvador M.
18 1.5. Leer datos de un archivo
return ret;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2. Interfaces funcionales
En esta sección se generaliza el programa de lectura de un archivo de texto para generar un tipo
de dato denominado ArrayDataset el cual abstrae el proceso para trabajar con un conjunto de
datos almacenados en un arreglo.
Figura 4. ArrayDataset
La clase ArrayDataset representa un arreglo de tamaño fijo y permite ejecutar varias acciones
sobre un arreglo de datos genérico:
Jaime Salvador M.
20 2. Interfaces funcionales
ds1=[1,2,3,4,5,6,7,8,9]
ds2=["uno","dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"]
ds1.count(): 9
ds1.first(): 1
ds1.last(): 9
ds1.min(): 1
ds1.max(): 9
ds1.minMax(): (1,9)
ds1.forEach(System.out::println)`: imprime todos los elementos
ds1.take(2): [1,2]
ds1.takeLast(2): [8,9]
ds1.takeWhile(it->it%2!=0): [1]
ds1.skip(2): [3,4,5,6,7,8,9]
ds1.skipLast(2): [1,2,3,4,5,6,7]
ds1.skipWhile(it->it%2!=0): [2,3,4,5,6,7,8,9]
ds1.filter(it->it%2==0): [2,4,6,8]
ds1.all(it->it>5): false
ds1.any(it->it>5): true
ds1.contains(it->it.equals(5)): true
ds1.findFirst(it->it.equals(5)): 5
ds1.map(it->"0"+it): [01,02,03,04,05,06,07,08,09]
ds1.zip(ds2, Pair::of):
21
2.1. Gradle
Para esta sección se utilizará un proyecto Gradle[2] con la finalidad de automatizar la gestió de
dependencias.
2.2. Constructores
La clase ArrayDataset encapsula las operaciones que s epueden realizar con un arreglo de datos,
hace uso de tipos genéricos para representar cualquier tipo de dato. Para evitar que la clase
ArrayDataset pueda ser instanciada directamente, la clase incluye dos constructores privados:
Debido a que los contrustores de la clase son privados, la única forma de crear instancias es a
través de los métodos estáticos fromFile y fromArray.
2.3. Creación
El método fromFile permite crear instancias de la clase a partir de información almacenada en
un archivo de texto separado por comas (,):
Jaime Salvador M.
22 2.4. Operaciones de filtrado
if (!line.isBlank()) {
var tokens = line.split(",");
T item = parser.parse(tokens);
data[index] = item;
index++;
}
}
• first()
• last()
• take(n)
• takeLast(n)
23
• skip(n)
• skipLast(n)
• filter(condicion)
2.4.1. first
Retorna el primer elemento del conjunto de datos.
public T first() {
return data[0];
}
2.4.2. last
Retorna el último elemento del conjunto de datos.
public T last() {
return data[data.length - 1];
}
La implementación del método retorna el último elemento (índice length-1) del arreglo.
2.4.3. take
Retorna los primeros n-elementos del arreglo y genera una nueva instancia de la clase
ArrayDataset.
❶ Se crea un nuevo arreglo que contiene count-elementos. El arreglo contiene el mismo tipo de
elementos que el vector original (genérico T)
❷ Se copian los primeros count-elementos elementos al nuevo arreglo
❸ Se crea una nueva instancia de la clase ArrayDataset
Jaime Salvador M.
24 2.4. Operaciones de filtrado
2.4.4. takeLast
Retorna los últimos n-elementos del arreglo y genera una nueva instancia de la clase
ArrayDataset.
int index = 0;
for (int i = this.data.length-size; i <this.data.length;i++) { ❷
tmpData[index++] = this.data[i];
}
❶ Se crea un nuevo arreglo que contiene count-elementos. El arreglo contiene el mismo tipo de
elementos que el vector original (genérico T)
❷ Se copian los últimos count-elementos al nuevo arreglo
❸ Se crea una nueva instancia de la clase ArrayDataset
2.4.5. skip
Ignora los primeros n-elementos del arreglo y retorna un nuevo arreglo con los elementos
restantes. Genera una nueva instancia de la clase ArrayDataset.
int index = 0;
for (int i = count; i < this.data.length; i++) { ❸
tmpData[index] = this.data[i];
index++;
}
❶ Si el número de elementos a ignorar es mayor que el tamaño del arreglo, se retorna un arreglo
vacío
25
2.4.6. skipLast
Ignora los últimos n-elementos del arreglo y retorna un nuevo arreglo con los elementos restantes.
Genera una nueva instancia de la clase ArrayDataset.
int index = 0;
for (int i = 0; i <size;i++) { ❸
tmpData[index++] = this.data[i];
}
❶ Si el número de elementos a ignorar es mayor que el tamaño del arreglo, se retorna un arreglo
vacío
❷ Se crea un nuevo arreglo que contiene length-count-elementos. El arreglo contiene el mismo
tipo de elementos que el vector original (genérico T)
❸ Se copian los últimos count-elementos elementos al nuevo arreglo
❹ Se crea una nueva instancia de la clase ArrayDataset
2.4.7. filter
Copia todos los elementos de un arreglo que cumplem una condición especificada. Genera una
nueva instancia de la clase ArrayDataset. A manera de ejemplo, si se tiene elarreglo:
datos = [1,5,7,4,2,3,5,8]
La llamada al método filter(esImpar) retornará el arreglo [1,5,7,3,5], es decir copia todos los
elementos del arreglo que cumplen la condición (esImpar).
Jaime Salvador M.
26 2.5. Operaciones condicionales y booleanas
}
}
int index = 0;
for (T it : data) { ❸
if (pred.test(it)) {
tmpData[index] = it;
index++;
}
}
• all(condicion)
• any(condicion)
• contains(condicion)
• takeWhile(condicion)
• filter(condicion)
2.5.1. all
Retorna true si todos los elementos del arreglo cumplen con la condición.
2.5.2. any
Retorna true si al menos un elemento del arreglo cumple con la condición.
}
}
return false;
}
2.5.3. contains
Retorna true si el arreglo contiene el elemento.
2.5.4. takeWhile
Descarta los elementos de un arreglo después de que una condición especificada se convierta en
falsa. Genera una nueva instancia de la clase ArrayDataset. A manera de ejemplo, si se tiene
elarreglo:
datos = [1,5,7,4,2,3,5,8]
int index = 0;
for (T it : data) { ❸
if (pred.test(it)) {
tmpData[index] = it;
index++;
} else {
break;
}
Jaime Salvador M.
28 2.5. Operaciones condicionales y booleanas
2.5.5. skipWhile
Descarta los elementos de un arreglo hasta que una condición especificada se convierta en falsa.
Genera una nueva instancia de la clase ArrayDataset. A manera de ejemplo, si se tiene elarreglo:
datos = [1,5,7,4,2,3,5,8]
int count = 0; ❶
while(count<this.data.length && pred.test(this.data[count])) {
count++;
}
int index = 0;
for(int i=count;i<this.data.length;i++) { ❸
tmpData[index++] = this.data[i];
}
[1] www.oracle.com/technical-resources/articles/java/javareflection.html
[2] gradle.org