Buenas Prácticas de Programación en Java
Buenas Prácticas de Programación en Java
1. BUENAS PRACTICAS.........................................................................................4
1.1 CamelCase........................................................................................................4
1.6 Trata de usar más las Interfaces sobre las Clases Abstractas......................7
1.8 Trata de usar librerías estándar en lugar de hacer las tuyas desde cero......7
1.9 Siempre que sea posible trata de usar tipos primitivos en lugar de las clases
Wrapper...................................................................................................................8
2. VARIABLES........................................................................................................11
3. CARACTERES ESPECIALES............................................................................13
4. OPERADORES (Todos).....................................................................................13
4.1 Aritméticos.......................................................................................................13
4.2 Relación...........................................................................................................13
4.3 Lógicos............................................................................................................ 14
4.4 Unitarios.......................................................................................................... 15
1
4.5 A nivel de bits.................................................................................................. 15
4.6 Asignación.......................................................................................................16
4.7 Condicional......................................................................................................17
4.8 Jerarquía......................................................................................................... 18
5.1 break................................................................................................................19
5.2 continue...........................................................................................................20
8.7 Interfaces..................................................................................................... 27
8.9 Polimorfismo................................................................................................ 29
9. PROGRAMACIÓN EN JAVA..............................................................................33
2
9.3 Bloques de inicialización estáticos y no estáticos........................................35
9.5 InstanceOf....................................................................................................38
9.6 JavaBeans................................................................................................... 42
9.9 Generics.......................................................................................................50
3
1. BUENAS PRACTICAS
1.1 CamelCase
CamelCase es un estilo de escritura que se aplica a frases o palabras compuestas.
El nombre se debe a que las mayúsculas a lo largo de una palabra en CamelCase
se asemejan a las jorobas de un camello. El nombre CamelCase se podría traducir
como Mayúsculas/Minúsculas Camello.
Los nombres de las clases deben ser sustantivos, en mayúsculas y minúsculas, con
la primera letra de cada palabra interna en mayúscula. El nombre de las interfaces
también debe estar en mayúscula (la primera) al igual que los nombres de las
clases. Use palabras completas y debe evitar acrónimos y abreviaturas.
Métodos en Java
Los métodos deben ser verbos, en mayúsculas y minúsculas, con la primera letra de
cada palabra interna (a partir de la segunda) en mayúscula.
Variables en Java
Debería estar todo en mayúsculas con palabras separadas por guiones bajos (“_”).
4
o Hay varias constantes utilizadas en clases predefinidas como Float,
Long, String, etc.
Paquetes en Java
La mejor práctica como mucho de ustedes saben, es definir siempre estas variables
como privadas y crear los métodos accesores, “setters“ y “getters”
5
Pero escribir los métodos accesores no resuelve el problema del todo. El arreglo
sigue siendo accesible. La mejor forma de hacerlo inmodificable es devolviendo un
arreglo clonado en lugar del arreglo mismo. Esto se logra modificando el método
get de la siguiente forma.
Para hacer una clase inmutable puedes definir sus constructor de forma privada y
luego crear un método estático para inicializar al objeto y devolverlo.
6
1.6 Trata de usar más las Interfaces sobre las Clases Abstractas
No es posible la herencia múltiple en Java, pero definitivamente puedes
implementar múltiples interfaces. Esto hace que cambiar la implementación de una
clase existente sea fácil y que puedas implementar una o más interfaces en lugar de
cambiar la jerarquía completa de la clase.
Pero si tú estás cien por ciento seguro de que métodos de una interface tendrás,
entonces solo implementa esa interfaz. Es bastante difícil agregar un nuevo
método en una interfaz existente sin alterar todo el código que se está
implementando. Por el contrario, un nuevo método puede ser fácilmente agregado
en una clase abstracta sin alterar la funcionalidad existente.
1.8 Trata de usar librerías estándar en lugar de hacer las tuyas desde cero
Escribir código es divertido. Pero no reinventes la rueda. Es bastante
recomendable usar librerías estándar que ya han sido probadas, debugeadas y
usadas por otros. Esto no sólo mejora la eficiencia de un programador, sino que
reduce las posibilidades de tener errores en el código. Además, usar una librería
estándar hace al código más legible y mantenible.
Por ejemplo, Google tiene liberada la nueva librería Google Collections que puede
ser usada para agregar más funcionalidad a tu código.
7
1.9 Siempre que sea posible trata de usar tipos primitivos en lugar de las
clases Wrapper
Las clases Wrapper son buenas, pero también son lentas. Los tipos primitivos son
como clases, sin embargo, las clases wrapper almacenan la información completa
acerca de una clase.
Además, si estás usando una clase wrapper no debes olvidar inicializarla. Porque el
valor por default de las variables wrapper es null.
8
1.10 Usa los Strings con mucho cuidado
Usa siempre las cadenas con mucho cuidado en tu código. Una simple
concatenación de cadenas puede reducir el rendimiento de tu programa. Por
ejemplo, si queremos concatenar cadenas usando el operador “+” en un ciclo for
entonces todo el tiempo se estará creando un objeto String. Esto afecta tanto a la
memoria como al rendimiento.
Además, en lugar de que instancies una objeto String no uses su constructor, sino
que debes instanciarlo directamente. Por ejemplo:
9
Ahora podríamos tener el siguiente código que use al objeto Estudiante.
En el código siguiente creamos tan solo al objeto Estudiante con algunas fechas de
nacimiento por default. Pero entonces cambiamos el valor del año de nacimiento.
¡Después imprimimos el año de nacimiento, este año fue cambiado por 2019!
Para evitar estos casos, se puede utilizar el mecanismo defensivo copias. Cambie el
constructor de la clase del estudiante a lo siguiente.
Esto para asegurarnos de tener otra copia de la fecha de nacimiento que usamos en
clase Estudiante.
10
2. VARIABLES
11
declararlos infiriéndose de la interfaz que implementan. La inferencia de tipos es la
idea que permite al compilador obtener el tipo estático sin que sea necesario
escribirlo de forma explícita.
12
3. CARACTERES ESPECIALES
Acción Representación
Salto de línea \n
Tabulador \t
Retroceso \b
Comilla simple \’
Comilla doble \”
Ir al principio de la línea \r
Nueva página \f
Barra inversa \\
Carácter Unicode. \udddd
Espacio \s
4. OPERADORES (Todos)
4.1 Aritméticos
Nombre Operador Acción
Suma + Suma
Resta - Resta
Multiplicación * Multiplica
División / Divide
Módulo o Resto % Obtiene el residuo de la
división
4.2 Relación
Nombre Operador Acción
Menos que < Menos que: el resultado
verdadero si el valor del
lado izquierdo es inferior al
del lado derecho.
Mayor que > Mayor que: devuelve
verdadero si el valor del
lado izquierdo es mayor que
13
el lado derecho.
Menor o igual que <= Menor o igual que:
devuelve verdadero si el
valor del lado izquierdo es
menor o igual que el lado
derecho.
Mayor o igual a >= Mayor que o igual a:
regresa verdadero si el valor
del lado izquierdo es mayor
o igual que el lado derecho.
No igual a: != No igual a: devuelve
verdadero si el valor del
lado izquierdo no es igual al
lado derecho.
Operador de igualdad == Igual a: devuelve verdadero
si el valor del lado izquierdo
es igual al lado derecho
4.3 Lógicos
Nombre Operador Acción
Operador condicional doble && Todas tienen que cumplir
(AND) con la condición (Evalúa en
modo corto circuito)
Operador condicional & Todas tienen que cumplir
simples (AND) con la condición (Evalúa
todas los condicionales)
Operador condicional doble || Por lo menos alguna tiene
(OR) que cumplir con la condición
(Evalúa en modo corto
circuito)
Operador condicional | Por lo menos alguna tiene
simples (OR) que cumplir con la condición
(Evalúa todas los
condicionales)
14
Operador unitario de ! Invierte el valor de una
negación variable booleana
Operador XOR ^ Devuelve true si ambos
valores son diferentes; de lo
contrario, devuelve false.
4.4 Unitarios
Nombre Operador Acción
Operador bit a bit de ~ Este es un operador unario
complemento (NOT) que devuelve la
representación
complementaria del valor de
entrada, es decir, con todos
los bits invertidos. El
resultado binario final se
muestra en decimal.
Operador de decremento - Cambie el signo de la
variable:
(Se coloca a la izquierda de
la variable)
15
resultado 0. El resultado
binario final se muestra en
decimal.
Operador bit a bit XOR ^ Si uno de los bits de entrada
es 0 y el otro 1, el resultado
es 1. Si ambos bits
comparados son iguales, el
resultado es 0. El resultado
binario final se muestra en
decimal.
Operador de << desplaza los bits del número
desplazamiento a la hacia la izquierda y llena
izquierda con “0” los bits desplazados.
Efecto similar a la
multiplicación del número
con una potencia de dos.
Operador de >> Desplaza los bits del
desplazamiento a la número a la derecha y llena
derecha firmado con “0” los bits desplazados.
El bit más a la izquierda
depende del signo del
número inicial. Efecto
similar a partir de dividir el
número con alguna potencia
de dos.
Operador de cambio a la >>> Desplaza los bits del
derecha sin signo número a la derecha y llena
con “0” los bits desplazados.
El bit más a la izquierda se
establece en 0.
4.6 Asignación
Nombre Operador Acción
Operador de incremento - ++ Incrementa el valor en 1
pre incremento y pos
16
incremento
4.7 Condicional
Nombre Operador Acción
Operador ?: Simplifica el If else en una simple línea de código:
ternario
17
4.8 Jerarquía
La regla de precedencia establece que los operadores de mayor nivel se ejecuten
primero:
Precedencia de operadores
Descripción Operadores
suma y resta +-
equivalencia == !=
operador XOR ^
operador OR |
OR booleano ||
condicional ?:
18
5. USO DE BREACK Y CONTINUE
En java hay dos sentencias que nos permiten forzar la salida de un bucle, y estas
sentencias son break (para salir completamente del bucle) y continue (para salir de
la iteración actual y saltar directamente a la siguiente).
Estas instrucciones siempre irán dentro de algún if (o else) porque carece de sentido
si se va a ejecutar siempre pues en ese caso está claro que hay algo que estamos
haciendo mal porque una parte de nuestro código no llegará a ejecutarse nunca.
5.1 break
La sentencia break hace que se salga del bucle inmediatamente por lo que no se
ejecutara ni el código que se encuentre después del break en esa misma iteración ni
ninguna de las posibles iteraciones restantes.
Esta sentencia no es exclusiva para los bucles y de hecho su uso más conocido es
dentro de un switch.
19
5.2 continue
Con continue se puede detener la ejecución de la iteración actual y saltar a la
siguiente. El caso normal de uso de continue es cuando dentro de un bucle estamos
haciendo muchas comprobaciones y en caso de que se cumpla alguna no hace falta
seguir comprobando el resto, pero no queremos meter unas comprobaciones
anidadas dentro de otras para una mayor legibilidad.
20
6. PRECEDENCIA DE OPERADORES (PRIORIDAD Y ORDEN DE
EVALUACIÓN)
21
7. MEMORIA STACK Y HEAP
22
8.3 Modificadores de acceso
Default (Es invisible)
Publico (public)
Privado (private)
private, por otro lado, es el modificador más restrictivo y especifica que los
elementos que lo utilizan sólo pueden ser accedidos desde la clase en la que se
encuentran. Este modificador sólo puede utilizarse sobre los miembros de una clase
y sobre interfaces y clases internas, no sobre clases o interfaces de primer nivel,
dado que esto no tendría sentido.
Protegido (protected)
El modificador protected, por último, indica que los elementos sólo pueden ser
accedidos desde su mismo paquete (como el acceso por defecto) y desde cualquier
clase que extienda la clase en que se encuentra, independientemente de si esta se
encuentra en el mismo paquete o no. Este modificador, como private, no tiene
sentido a nivel de clases o interfaces no internas.
23
8.4 Miembros estáticos de una clase
Para definir una propiedad o método estático en lenguaje Java se antepone el
modificador static a su nombre.
Las propiedades estáticas de una Clase son compartidas por todos los Objetos que
heredan de ella, con lo que si su valor es modificado en cualquier de ellos afectará a
todas las demás instancias.
Por otro lado, para acceder a los métodos estáticos de una clase no es necesario
crear un objeto, pudiendo acceder a ellos a través del propio nombre de clase.
Un Atributo static:
Podemos considerarlo como una variable global a la que tienen acceso todos los
objetos de la clase.
[Link]
Un Método static:
24
NombreClase.método()
Terminología importante
¿Qué es Herencia?
25
8.6 Clases y métodos abstractos
Clase abstracta
Métodos abstractos
26
extiende. También tiene implementaciones de todos los métodos de
interfaces que implementa.
8.7 Interfaces
Permiten simular la herencia múltiple
La interfaz solo es public o default
Las interfaces no heredan de la clase object
Las intefaces no tienen constructores
Todos sus métodos son públicos y abstractos
Todos sus atributos son constantes (public, static y final)
Cuando creamos una interface, el nombre del archivo comienza con “I”,
ejemplo: IAccesoDatos
Por lo tanto, una interfaz especifica qué se debe hacer, pero no cómo hacerlo. Una
vez que se define una interfaz, cualquier cantidad de clases puede implementarla.
Además, una clase puede implementar cualquier cantidad de interfaces.
27
8.8 Diferencia entre clase e interfaz
Use una clase abstracta cuando se necesita definir una plantilla para un
grupo de subclases
Use una interfaz cuando se debe definir un rol para otras clases,
independientemente del árbol de herencia de estas clases
28
En el momento de la declaración, la variable de interfaz debe inicializarse. De
lo contrario, el compilador lanzará un error.
La clase no puede implementar dos interfaces en Java que tengan métodos
con el mismo nombre, pero diferente tipo de devolución.
Resumen:
8.9 Polimorfismo
El polimorfismo es una característica de la programación orientada a objetos que
permite llamar a métodos con igual nombre pero que pertenecen a clases distintas.
En Java es necesario que las clases compartan una superclase común para
implementar el polimorfismo, luego veremos que también se puede implementar el
polimorfismo en Java mediante interfaces.
Ejemplo:
29
8.10 Upcasting vs Downcasting
La tipificación es uno de los conceptos más importantes que básicamente se ocupa
de la conversión de un tipo de datos a otro de forma implícita o explícita. En este
artículo, se analiza el concepto de encasillamiento de objetos.
Al igual que los tipos de datos, los objetos también se pueden tipificar. Sin embargo,
en los objetos, solo hay dos tipos de objetos (es decir, objeto principal y objeto
secundario). Por lo tanto, el encasillado de objetos significa básicamente que un tipo
de objeto (es decir) hijo o padre de otro. Hay dos tipos de encasillamiento. Son:
30
Upcasting: Upcasting es el encasillado de un objeto hijo a un objeto padre .
El upcasting se puede hacer implícitamente. Upcasting nos da la flexibilidad
de acceder a los miembros de la clase principal, pero no es posible acceder a
todos los miembros de la clase secundaria utilizando esta función. En lugar
de todos los miembros, podemos acceder a algunos miembros específicos de
la clase secundaria. Por ejemplo, podemos acceder a los métodos anulados.
Downcasting: De manera similar, downcasting significa encasillar un objeto
padre a un objeto hijo . El abatimiento no puede ser implícito.
31
utiliza super para invocar al constructor de la superclase desde en constructor de la
subclase.
Una variable con modificadores static y final sería lo más cercano en Java a las
constantes de otros lenguajes de programación.
32
9. PROGRAMACIÓN EN JAVA
En esta situación, sería conveniente pasar solo los argumentos a los que no se
aplicaron los valores predeterminados. Crear dicho método implica que debe haber
alguna forma de crear una lista de argumentos que sea de longitud variable, en
lugar de fija.
Salida:
33
NOTA: Si existen varios parámetros, el parámetro variable debe ser el último.
En su forma más simple, una enumeración es una lista de constantes con nombre
que definen un nuevo tipo de datos. Un objeto de un tipo de enumeración solo
puede contener los valores definidos por la lista. Por lo tanto, una enumeración le
brinda una manera de definir con precisión un nuevo tipo de datos que tiene un
número fijo de valores válidos.
Desde una perspectiva de programación, las enumeraciones son útiles siempre que
necesite definir un conjunto de valores que represente una colección de elementos.
Por ejemplo, puede usar una enumeración para representar un conjunto de códigos
de estado, como éxito, espera, error y reintentos, que indican el progreso de alguna
acción. En el pasado, dichos valores se definían como variables finales, pero las
enumeraciones ofrecen un enfoque más estructurado.
Ejemplo:
34
Enun con constructores y métodos:
Ejemplo:
35
Clase:
Main:
Salida:
36
9.4 Autoboxing y Unboxing
A partir de JDK 5, Java ha incluido dos características muy útiles: autoboxing y auto-
unboxing. El autoboxing/unboxing simplifica y agiliza en gran medida el código que
debe convertir los tipos primitivos en objetos, y viceversa. Debido a que tales
situaciones se encuentran con frecuencia en el código de Java, los beneficios del
autoboxing/unboxing afectan a casi todos los programadores de Java.
Cada uno de los tipos primitivos tiene una clase en java asociada conocida como
clase Wrapper o Envolvente
37
Ejemplo:
9.5 InstanceOf
Las palabra “instance of” nos ayudará a determinar el tipo de un objecto en tiempo
de ejecución, por lo tanto, esta palabra nos permitirá realizar la siguiente pregunta:
¿De qué tipo es la referencia a la cual está apuntando cierta variable?
En este caso las dos variables son de tipo Son, aunque la segunda se halla
almacenado en una variable de tipo Father, lo importante es el tipo la referencia.
Ejemplo 1
38
Entrada:
Salida:
Ejemplo 2
Entrada:
Salida:
Ejemplo 3
Entrada:
39
Salida:
Ejemplo 4
Entrada:
Salida:
40
Ejemplo 5
La razón es sencilla: cuando se utiliza una clase, como en este caso, instanceof solo
devuelve false en dos casos:
41
9.6 JavaBeans
Para que una clase en java se considere “JavaBean” debe de tener las siguientes
características:
Ejemplo de JavaBean:
42
9.7 Excepciones (Exception)
El lenguaje Java utiliza excepciones para proporcionar posibilidades de manejo de
errores para sus programas. Una excepción es un evento que se produce cuando se
ejecuta el programa de forma que interrumpe el flujo normal de instrucciones.
Salida:
43
Nota: Si la clase hereda de “Exception”, el compilador nos obliga a porcesar la
exception, sin embargo, si heredamos de la clase “RuntimeException” el compilador
no nos obligará a capturar la excepción (Esto lo podemos evidenciar en las
operaciones sobre “0”, ya que el compilador nos permite realizar la operación, y el
error solo salta cuando se ejecuta el programa).
44
Salida:
45
Finalmente, al utilizar el método, el compilador no nos obligará a capturar la
excepción:
Salida:
Esta interfaz es “la raíz” de todas las interfaces y clases relacionadas con
colecciones de elementos. Algunas colecciones pueden admitir duplicados de
elementos dentro de ellas, mientras que otras no admiten duplicados. Otras
colecciones pueden tener los elementos ordenados, mientras que en otras no existe
orden definido entre sus elementos. Java no define ninguna implementación de esta
interface y son respectivamente sus subinterfaces las que implementarán sus
métodos como son por ejemplo las interfaces Set o List (que son subinterfaces de
Collection).
46
Una colección es de manera genérica un grupo de objetos llamados elementos.
Esta interfaz por tanto será usada para pasar colecciones de elementos o
manipularlos de la manera más general deseada.
Tipos de colecciones
47
El uso de listas en Java es una forma útil de almacenar y manipular grandes
volúmenes de datos, tal como haríamos en una matriz o arreglo, pero con una serie
de ventajas que hacen de este tipo de variables las preferidas para el
procesamiento de grandes cantidades de información.
Las listas en Java son variables que permiten almacenar grandes cantidades de
datos. Son similares a los Array o a las Matrices. Sin embargo, las nuevas
tendencias en la programación van orientadas hacia el uso de Listas para el manejo
de grandes volúmenes de datos. De hecho, Java 8, dentro de sus nuevas
herramientas de programación (específicamente las expresiones Lambda), posee
muchas funcionalidades interesantes implementando listas, lo cuales nos permitirá
lograr muchas cosas fabulosas de una manera mucho más rápida y fácil de lo que
haríamos antes (sin embargo, esto es contenido para otro post).
Algo que me llama mucho la atención de las listas en Java es el hecho de que no es
necesario establecer un tamaño específico para la variable, a diferencia de las
tradicionales matrices o arreglos. Las listas son sumamente versátiles y mucho más
fáciles de manejar que otros tipos de variables de agrupación de datos.
Este tipo de lista puede almacenar cualquier tipo de dato, pero este enfoque ya ha
quedado obsoleto. Se prefiere que se designe el tipo de dato que se va a
almacenar. Entonces para declarar una lista donde guardaremos datos tipo String,
hacemos lo siguiente:
48
Supongamos que queremos agregar los siguientes nombres: Juan, Pedro, José,
María, Sofía.
Hacemos lo siguiente:
49
Para concluir, en la siguiente imagen se puede apreciar las 3 interfaces principales
de Collection, apartarte de la interfaz Map, para más detalles investigar el uso de
cada intefaz, y sus implementaciones.
9.9 Generics
Hace ya más de una década que en Java 5 se introdujeron los generics para dotar
al lenguaje de una mejor comprobación de tipos en tiempo de compilación y al
mismo tiempo eliminar los cast que hasta entonces eran necesarios al usar las
colecciones. Dada la lentitud de adopción que suele haber en la plataforma Java en
los grandes entornos empresariales puede que aún no los hayamos usado
extensamente o tengamos alguna duda en su uso. Hay unos cuantos conceptos
sobre los generics que son convenientes conocer.
Los generics fueron introducidos en la versión 5 de Java en 2004 junto con otras
muchas novedades suponiendo en su historia una de las mayores modificaciones o
al mismo nivel de las novedades introducidas con Java 8 más recientemente al
lenguaje Java. Los generics son importantes ya que permiten al compilador informar
de muchos errores de compilación que hasta el momento solo se descubrirían en
tiempo de ejecución, al mismo tiempo permiten eliminar los cast simplificando,
reduciendo la repetición y aumentando la legibilidad el código. Los errores por cast
50
inválido son especialmente problemáticos de debuggear ya que el error se suele
producir en un sitio alejado del de la causa.
Los generics permiten usar tipos para parametrizar las clases, interfaces y métodos
al definirlas. Los beneficios son:
Un tipo usando generics tiene el siguiente aspecto, por ejemplo, usando una clase
Box contenedor de una referencia a un tipo no determinado en la definición de la
clase pero que lo será en su uso. Una clase genérica puede tener múltiples
argumentos de tipos y los argumentos pueden ser a su vez tipos genéricos.
Después del nombre de la clase se puede indicar la lista de parámetros de tipos con
el formato \<T1, T2, T3, ...\>.
51
A continuación, veremos un breve ejemplo de tipos genéricos:
Método main:
52