Mi presentación en el #JavaDaySTI2018 sobre consejos prácticos que nos ayudarán a desarrollar software con menos bug en Java @JavaDominicano @ComitesISC
Fundamentos de Java / 15 consejos prácticos sobre Java que cambiarán la forma en que codificas
1. FUNDAMENTOS DE JAVA
15 consejos prácticos sobre Java que cambiarán la forma en que codificas
Java Day Santiago RD 2018
12 Mayo 2018, Pontificia Universidad Católica Madre y Maestra (PUCMM), Santiago, R. D.
@JavaDominicano #JavaDaySTI2018
Eudris Cabrera
@eudriscabrera
2. Eudris Cabrera
Graduado de Ingeniería Telemática en la PUCMM.
Entusiasta de la tecnología y el software libre,
desarrollador Java, instructor ocasional (Java / Linux),
aficionado del béisbol/sóftbol y los bailes latinos.
En el tiempo libre, escribe artículos, realiza charlas,
participa en eventos tecnológicos y ayuda en la
revisión de documentación técnica en el mundo Java y
el código abierto.
3. AGENDA
● 15 consejos prácticos sobre características
fundamentales que todo programador Java debe
tener en cuenta.
● Conocer técnicas y mejores prácticas para producir
software con menos bug en Java.
● Extras
5. Tipos
Primitivos
(sin métodos; no son
objetos; no necesitan
una invocación para
ser creados)
Nombre Tipo
Espacio
Memoria
Rango
Aproximado
Valor por
defecto
Clase
Asociada
byte Entero 1 byte -128 a 127 0 Byte
short Entero 2 bytes -32768 a
32767
0 Short
int Entero 4 bytes 2*109 0 Integer
long Entero 8 bytes Muy grande 0L Long
float Decimal simple 4 bytes Muy grande 0.0f Float
double Decimal doble 8 bytes Muy grande 0.0d Double
char Carácter simple 2 bytes 'u0000' Character
boolean Valor true o
false
1 byte false Boolean
void Void
6. Tipos
Objeto
(con métodos, necesitan
una invocación para ser
creados)
Nombre Tipo
Tipos de la biblioteca estándar
de Java
String (cadenas de texto)
Muchos otros (p.ej. Scanner, TreeSet, ArrayList…)
Tipos definidos por el
programador / usuario
Cualquiera tipo que se nos ocurra
arrays Serie de elementos o formación tipo vector o matriz.
Lo consideraremos un objeto especial que carece
de métodos.
Tipos envoltorio o wrapper
(Equivalentes a los tipos
primitivos pero como objetos.)
Byte
Short
Integer
Long
Float
Double
Character
Boolean
8. Paquetes de Propósito General
java.lang
Contiene clases fundamentales e interfaces fuertemente relacionadas con el lenguaje y el sistema runtime.
java.io
Las clases centrales del paquete son InputStream y OutputStream, las cuales son clases abstractas, base para leer y
escribir a streams de bytes, respectivamente.
java.nio
El paquete java.nio (NIO o Nueva I/O) fue añadido para soportar I/O mapeada en memoria, facilitando las
operaciones I/O cercanas al hardware subyacente con mejor rendimiento.
Java.text
El paquete java.text proporciona clases e interfaces para el manejo de texto, fechas, números y mensajes de una
manera independiente de los lenguajes naturales.
9. Paquetes de Propósito General
java.math
Soporta aritmética multi precisión (incluyendo operaciones aritméticas modulares) y suministra generadores de números
primos multi precisión usados para la generación de claves criptográficas.
java.util
En el paquete está incluida la API Collections, una jerarquía organizada de estructura de datos influenciada fuertemente por
consideraciones de patrones de diseño.
java.net
El paquete java.net suminista rutinas especiales IO para redes, permitiendo las peticiones HTTP, así como también otras
transacciones comunes.
10. Paquetes de Propósito Especial
java.sql
Una implementación de la API JDBC (usada para acceder a bases de datos SQL) se agrupa en el paquete java.sql.
java.time
La API principal de fechas, horas, instantes, y duraciones.
12. Clase String
Se utiliza para manejar cadena de texto.
Algunos consejos a la hora de manejar cadena de texto
● Evitar concatenar usando el signo de más (+), usar el método concat o join para tales fines.
● Utilizar el método format(String format, Object... args)
● Para cadenas grandes de caracteres usar StringBuilder
13. Clase StringBuilder
Util para manejar grandes cadenas de texto
● Es considerable tomar el cuenta el valor por defecto cuando creamos una instancia de este tipo
● Si la cadena es muy grande inicializar el constructor con un valor alto
● Evitar concatenar usando el signo de más (+), utilice el método append()
15. Clases Genéricas
Las clases genéricos permiten usar tipos para parametrizar las clases, interfaces y métodos al definirlas. Los
beneficios son:
● Comprobación de tipos más fuerte en tiempo de compilación.
● Eliminación de casts aumentando la legibilidad del código.
● Posibilidad de implementar algoritmos genéricos, con tipado seguro.
17. Enums
Un dato de un tipo enumerado es aquel que puede tomar por valor uno de los pertenecientes a una lista
ordenada de valores definida por el programador.
Ejemplo:
public enum Genero {
MASCULINO, FEMENINO;
}
19. Manejo de Excepciones
● Gestionar correctamente todas o la mayor parte de los errores que se pueden producir.
● Evitar mostrar al usuario los mismos mensajes generados por las excepciones, en su lugar colocar
mensajes personalizados que el usuario final pueda entender sin problemas.
● Crear clases personalizadas para manejar nuestras excepciones.
● Evitar escribir en la consola usando printStackTrace(), en su lugar usar un Logger
● Usar multiples catch de excepciones
21. Java Logging API
Podemos usar el framework de logging de Java para:
- Escribir mensajes a la consola
- Escribir mensajes en un archivo
22. La forma en que opera es la siguiente:
- Creamos un objeto estático de tipo Logger desde el cual enviaremos los mensajes.
● Creamos un objeto ConsoleHandler y se lo agregamos al Logger, de modo que los mensajes
aparezcan automáticamente en la consola.
● Creamos un objeto FileHandler y se lo agregamos al Logger, este Handler en particular enviara los
mensajes al archivo que le indiquemos.
● Creamos un objeto SimpleFormatter y lo establecemos en el FileHandler, de este modo los logs se
escriban como texto plano simple, de no indicarlo se escribiran en formato XML por defecto.
- Para registrar algo en bitácora llamamos al método log del Logger indicamos el nivel del log y el mensaje
que deseamos registrar, esto automáticamente reportara la fecha, hora, el nombre completo de la clase
y el método y en el caso de mensajes de nivel grave la linea de código donde se genero el reporte
23. Niveles de Log
Podemos indicar el nivel de información que queremos guardar o mostrar en la consola usando los diferentes
niveles. En orden descendente
SEVERE (más alto nivel)
WARNING
INFO
CONFIG
FINE
FINER
FINEST (más bajo nivel)
25. Uso de try-with-resources
Cuando estamos trabajando con archivos, conexiones a base de datos, socket, etc., debemos manejar
correctamente los recursos correspondientes a cada uno de estos casos, esto es, cerrar cada recursos luego
de su uso para evitar problemas posteriores, como anidamientos de conexiones.
A partir de Java SE 7 se introdujo una forma sencilla de manejar los recursos try-with-resources.
27. Usando el try de esa forma nos aseguramos de que el recurso quede cerrado luego de su uso.
Esto es posible a que las clases anteriores implementa la interfaz Closable.
Se podrá utilizar try-with-resources siempre que implementen la interfaz Closable.
29. Tenemos una lista del tipo del tipo Team y sobre ella queremos realizar
algunas operaciones cumpliendo ciertos criterios.
public void
printTeamsHasNotWonWorldSeries(List<Team> teams){
for (Team team : teams) {
if(!team.isHasWonWoldSeries()){
System.out.println(""+ team.toString());
}
}
}
30. Ejemplo
public void printTeamsWithPredicate(List<Team> teams, Predicate<Team>
tester){
for (Team t : teams) {
if(tester.test(t)){
System.out.println(""+ t.toString());
}
}
}
Predicate<Team> hasNotWonWS = new Predicate<Team>() {
@Override
public boolean test(Team t) {
return !t.isHasWonWoldSeries();
}
};
printTeamsWithPredicate(teams, hasNotWonWS);
¿Cuál es el inconveniente de
esta solución?
Las clases anónimas reduce la cantidad
de clases creadas y el paso de
comportamiento como parámetro se
mantiene, pero aún se puede detectar
mucho código repetido.
Solución usando clases anónimas
31. En nuestro ejemplo anterior, podemos utilizar una expresión lambda en
lugar de una clase anónima.
Ejemplo básico usando expresiones lambdas.
printTeamsWithPredicate(teams, (Team t) -> !t.isHasWonWoldSeries());
Nota:
Puede parecer bastante confuso en un
principio, pero ya revisaremos los
conceptos y cambios en el lenguaje que
nos permitirán escribir código Java de
esa manera.
32. Expresiones lambdas
Una expresión lambda representa una
función anónima.
λx → x+x
Función anónima que toma un número x y devuelve el resultado x + x.
33. Una expresión lambda se compone de un conjunto de
parámetros, un operador lambda ( -> ) y un cuerpo de la
función.
34. Sintaxis
() -> System.out.println("Hello Lambda")
x -> x + 10
(int x, int y) -> { return x + y; }
(String x, String y) -> x.length() – y.length()
(int a, int b) -> a + b
(int a) -> a + 1
(int a, int b) -> {
System.out.println(a + b);
return a + b;
}
() -> new ArrayList();
37. API Stream
Stream:
● Representa una abstracción para
especificar cálculos agregados
(acumulativos).
● Simplifica la descripción de los cálculos
agregados (laziness,paralelismo).
38. Elementos de un Stream
Un Stream se compone de 3 elementos:
● Un origen
● Cero o más operaciones intermedias
● Una operación final (salida o un resultado)
42. Clase Optional
Ayuda a eliminar los problemas de NullPointerException
Optional<T>
Contenedor para una referencia de objet (nulo, o objeto real).
Piensa en Optional como un stream 0 ó 1 elemento.
Garantiza que la referencia de Optional no retornará nulo.
43. Ejemplo
Usando Optional con Stream
Optional<String> val = Stream.of("one", "two").findAny();
Optional<String> val = Stream.of("one", "two").findFirst();
Optional<Team> opt = teams.stream().findFirst();
Otros métodos útiles en la clase Optional
opt.isPresent(); //true
Optional<Team> opt = Optional.empty();
opt.orElse(new Team("TOR", "Toronto Blue Jays", true, 1992)).isHasWonWoldSeries();
45. Date Time API JSR 310
Nuevo API de fecha/tiempo en java
46. Date Time API
El Date and Time API se desarrolló como parte del Java Community Process (JCP) dirigido por Stephen
Colebourne (autor de Joda-Time) y Oracle, bajo JSR 310.
El paquete java.time es el núcleo de la API y utiliza el sistema de calendario definido en ISO-8601
(https://www.iso.org/iso-8601-date-and-time-format.html ) como el calendario predeterminado.
El calendario ISO se basa en el sistema de calendario gregoriano y es el estándar internacional para
representar fecha y hora.
Para soportar las necesidades de los desarrolladores que utilizan sistemas de calendario no ISO, en
algunas áreas del mundo, como Japón o Tailandia, el nuevo API de Tiempo y Fecha permite trabajar con
diferentes sistemas de calendario.
47. java.time
LocalDate : Fecha más fácil de interpretar.
LocalDate date = LocalDate.now();
System.out.printf("%s-%s-%s", date.getYear(), date.getMonthValue(), date.getDayOfMonth());
LocalDateTime: Maneja fecha y hora sin especificar la zona horaria
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zdateTime = ZonedDateTime.now(); //fecha y hora con zona horaria
Zona Horaria
ZoneId zone = ZoneId.systemDefault();
Clock clockDefault = Clock.systemDefaultZone();
ZoneId zoneAmerica = ZoneId.of("America/Santo_Domingo");
Clock clock = Clock.system(zoneAmerica);
48. java.time
Haciendo cálculo de fechas
LocalDate sinceJava8Launch = LocalDate.of(2014, Month.MARCH, 18);
LocalDate today = LocalDate.now();
today.isAfter(sinceJava8Launch); //true
Calcular diferencia entre dos fecha usando period
LocalDate sinceBarCamp2013 = LocalDate.of(2013, Month.NOVEMBER, 16);
LocalDate currentDate = LocalDate.of(2015, Month.NOVEMBER, 28);
Period betweenDates = Period.between(sinceBarCamp2013, currentDate);
int diffInDays = betweenDates.getDays();
int diffInMonths = betweenDates.getMonths();
int diffInYears = betweenDates.getYears();
49. TemporalQuery
Determinar si una fecha es festiva
usando TemporalQuery
LocalDate date = LocalDate.of(2016,
Month.JANUARY, 26);
Boolean isHoliday = date.query(new
DiasFestivosRD());
public class DiasFestivosRD implements TemporalQuery<Boolean>{
static List<MonthDay> DIAS_FESTIVOS = Lists.newArrayList(
MonthDay.of(Month.JANUARY, 1), // Año Nuevo
MonthDay.of(Month.JANUARY, 6), // Día Santos Reyes
MonthDay.of(Month.JANUARY, 21), // Día de la Altagracia
MonthDay.of(Month.JANUARY, 26), // Día del Natalicio de
Duarte
MonthDay.of(Month.FEBRUARY, 27), // Día Independencia
Nacional
MonthDay.of(Month.MAY, 1), //Día Trabajador
MonthDay.of(Month.AUGUST, 16), //Día Restauración
MonthDay.of(Month.SEPTEMBER, 24), //Día de las Mercedes
MonthDay.of(Month.NOVEMBER, 6), //Día Constitución
MonthDay.of(Month.DECEMBER, 25) //Día de Navidad
);
@Override
public Boolean queryFrom(TemporalAccessor date) {
MonthDay diaMesActual = MonthDay.from(date);
return DIAS_FESTIVOS.contains(diaMesActual);
}
}
50. TemporalQuery
Determinar si una fecha es esta dentro de la temporada ciclónica
LocalDate date = LocalDate.of(2017, Month.JUNE, 30);
Boolean esTemporadaCiclonica = date.query(new TemporadaCiclonica());
public class TemporadaCiclonica implements TemporalQuery<Boolean>{
@Override
public Boolean queryFrom(TemporalAccessor temporal) {
LocalDate fecha = LocalDate.from(temporal);
MonthDay primeroJulio = MonthDay.of(Month.JUNE.getValue(), 1);
MonthDay trentaNoviembre = MonthDay.of(Month.NOVEMBER.getValue(), 30);
return fecha.isAfter(primeroJulio.atYear(fecha.getYear())) &&
fecha.isBefore(trentaNoviembre.atYear(fecha.getYear()));
}
}
52. Varargs en Java
Introducido en Java 5 y su objetivo es proporcionar una vía corta para los métodos que admiten un número
arbitrario de parámetros de un tipo.
Los varargs nos ayudan a evitar escribir un código repetitivo al introducir la nueva sintaxis que puede
manejar una cantidad arbitraria de parámetros automáticamente, usando una arreglo detrás de escenario.
public static void main(String... s) {}
Restrinciones:
Cada método solo puede tener un parámetro varargs.
El argumento varargs debe ser el último parámetro.
54. Clase Path
Forma parte de paquete java.nio y provee una forma fácil para trabajar con rutas. Es común usarla en
conjunto con la clase Files.
Ejemplo:
try (BufferedReader reader = Files.newBufferedReader(Paths.get("SonnetI.txt"), StandardCharsets.UTF_8)) {
long totalLines = reader.lines().count();
System.out.println("Number of lines = " + totalLines);
} catch (IOException ex) {
Logger.getLogger(DemoRecursos.class.getName()).log(Level.SEVERE,
ex.getMessage());
}
55. Clase Path
A partir de JDK8 se agregó el método lines () dentro de la clase Files.
Devuelve un Stream de elementos de cadena.
57. Sistema Modular :
Proyecto Jigsaw
Principal novedad en Java 9.
La idea de un sistema modular es hacer el jdk más
ligero para dispositivos pequeños.
El sistema de módulos proporcionará a la aplicación
la capacidad de utilizar sólo los módulos del jdk que
sean necesarios.
Las aplicaciones ya no necesitarán el jdk completo. El
sistema de módulos encapsula las clases públicas
dentro de un módulo. Así que clase definida pública no
estaría disponible para el mundo entero hasta que un
módulo lo defina explícitamente.
58. Sistema Modular - Proyecto Jigsaw
Los módulos van a ser descritos en un archivo llamado module-info.java ubicado en la
parte superior de la jerarquía de código java.
El archivo module-info provee:
1. Nombre del módulo.
2. Lista de dependencias de módulos necesarias para la correcta compilación y
ejecución.
3. Información sobre paquetes exportados por este módulo.
4. Lista de servicios que proporciona el módulo en tiempo de ejecución.
60. Sistema Modular - Proyecto Jigsaw
com.example.samplemodule : es el nombre del módulo.
requires : Indica que son dependencia del módulo
exports : Todas las clases públicas en estos paquetes serán accesibles a otros módulos
que dependen de él.
uses : Para usar datos de otros módulos.
provides : Proporciona configuración al servicio de otro módulo
61. Demo
Vamos a explorar varios ejemplos.
https://github.com/ecabrerar/java9-
labs/tree/master/jigsaw
67. Asuntos Legales
Todas las marcas registradas, así como todos los logotipos, imágenes,
fotografías, audio y vídeos mostrados en esta presentación son propiedad de
sus respectivos propietarios y/o representantes.
Su utilización es solamente para fines ilustrativos.
Ingeniero Telemático - PUCMM (2006). Desarrollador Java desde hace más de 9 años. Actualmente Desarrollador Informático en el Programa de Administración Financiera Integrada (PAFI) / Ministerio de Hacienda.
Entusiasta de la tecnología y el software libre, charlista ocasional y colaborador en eventos tecnológicos para desarrolladores como Barcamp RD, Taller de Java EE 7 /Java Day Santiago RD (PUCMM - Santiago), Code Camp SDQ 4.0, varias charlas y talleres en la Universidad Abierta para Adultos (UAPA-Santiago). Miembro fundador de la Comunidad Java Dominicano.
He sido Facilitador a tiempo parcial en el Curso Final de Grado de la Escuela de Ingeniería y Tecnología de la Universidad Abierta para Adultos (UAPA), Santiago. También, facilitador en el Diplomado de Programación Java organizado por la MESCYT y el Centro de Tecnología y Educación Permanente (TEP) de la PUCMM, Santiago.
Puede parecer bastante confuso en un principio, pero ya revisaremos los conceptos y cambios en el lenguaje que nos permitirán escribir código Java de esa manera.
Con las expresiones lambdas podemos crear código más conciso y significativo, además de abrir la puerta hacia la programación funcional en Java, donde las funciones juegan un papel fundamental.
La API Stream nos permite realizar operaciones de tipo filtro/mapeo/reducción sobre colecciones de datos de forma secuencial o paralela y su implementación es transparente para el desarrollador.