|
1 | | -# 🌎 Valor nulo |
| 1 | +# 🌎 POJO, Record |
2 | 2 |
|
3 | | -Una variable de referencia contiene información sobre la ubicación de un objeto. No contiene el objeto en sí. |
| 3 | +## POJO |
4 | 4 |
|
5 | | -Por ejemplo el siguiente código: |
| 5 | +Un _Plain old Java object (POJO)_ o objeto simple de Java es una clase que generalmente solo tiene campos o variables de instancia. |
6 | 6 |
|
7 | | -```java |
8 | | - String str; |
9 | | - Persona p; |
| 7 | +Se utiliza para alojar datos y pasar datos entre clases funcionales. Normalmente tiene pocos métodos o ninguno, además de los getters y setters. Se utiliza mayoritariamente para leer o escribir datos a partir de bases de datos, flujos o ficheros. Se podría decir que es un tipo de datos. |
| 8 | + |
| 9 | +### Ejemplos de POJOS |
| 10 | + |
| 11 | ++ A veces pueden ser llamados bean, o JavaBean. JavaBean es un POJO con extra reglas aplicadas a ellos. |
| 12 | ++ Otras veces un POJO puede ser un Entity, relacionado con base de datos porque contiene los datos de las entidades de base de datos. |
| 13 | ++ Otro acrónimo usando con los POJOS puede ser un DTO (data transfer object), objeto de transferencia de datos, que es una descripción de un objeto, que puede modelarse como simples datos. |
| 14 | + |
| 15 | +> Ejemplo de POJO que contiene el código necesario para manipular datos de un estudiante: |
| 16 | +
|
| 17 | +```java title="Student.java" |
| 18 | +public class Student { |
| 19 | + private String id; |
| 20 | + private String name; |
| 21 | + private String dateOfBirth; |
| 22 | + |
| 23 | + public Student(String id, String name, String dateOfBirth) { |
| 24 | + this.id = id; |
| 25 | + this.name = name; |
| 26 | + this.dateOfBirth = dateOfBirth; |
| 27 | + } |
| 28 | + |
| 29 | + public String getId() { |
| 30 | + return id; |
| 31 | + } |
| 32 | + |
| 33 | + public void setId(String id) { |
| 34 | + this.id = id; |
| 35 | + } |
| 36 | + |
| 37 | + public String getName() { |
| 38 | + return name; |
| 39 | + } |
| 40 | + |
| 41 | + public void setName(String name) { |
| 42 | + this.name = name; |
| 43 | + } |
| 44 | + |
| 45 | + public String getDateOfBirth() { |
| 46 | + return dateOfBirth; |
| 47 | + } |
| 48 | + |
| 49 | + public void setDateOfBirth(String dateOfBirth) { |
| 50 | + this.dateOfBirth = dateOfBirth; |
| 51 | + } |
| 52 | + |
| 53 | + @Override |
| 54 | + public String toString() { |
| 55 | + return "Student{" + |
| 56 | + "id='" + id + '\'' + |
| 57 | + ", name='" + name + '\'' + |
| 58 | + ", dateOfBirth='" + dateOfBirth + '\'' + |
| 59 | + '}'; |
| 60 | + } |
| 61 | +} |
10 | 62 | ``` |
11 | 63 |
|
12 | | -declara dos variables de referencia pero no construye ningún objeto. Con el siguiente código: |
| 64 | +!!! Note Importante |
| 65 | + Casi todo el código es generado con el IDE, es este caso, IntelliJ, que hace gran parte del trabajo por nosotros. Este tipo de código tiene un nombre, es lo que se conoce como **boilerplate code**, o código repetitivo que sigue un patrón. |
13 | 66 |
|
14 | | -```java |
15 | | - str = "Programación"; |
16 | | - p = new Persona("Patricia"); |
| 67 | +## Record |
| 68 | + |
| 69 | +Java introdujo un nuevo tipo llamado Record (registro) que pasó a formar parte oficialmente en el JDK 16. Su propósito es reemplazar el código boilerplate del POJO y ser más restrictivo. |
| 70 | + |
| 71 | +Java llama a los Record, "plain data carriers", soporte de datos simples. |
| 72 | + |
| 73 | +{++Record es una clase especial que contiene datos y no está pensada para ser alterada.++} Sólo contiene los métodos más fundamentales, como constructores y getters. |
| 74 | +El desarrollador no tiene que escribir nada de este código. |
| 75 | + |
| 76 | +### Cómo crear un Record |
| 77 | + |
| 78 | +Vamos a crear un record de estudiante como hicimos en el POJO anterior. Para ello, En el IntelliJ, dentro del proyecto, en un directorio hacemos botón derecho del ratón, _"New -> Java class"_. |
| 79 | + |
| 80 | + |
| 81 | + |
| 82 | +Seleccionamos la opción _"Record"_ (Necesito tener instalado JDK 16 o superiores) |
| 83 | + |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +Si nos fijamos en el código generado tenemos, el modificador de acceso `public` más la palabra `record` y luego el nombre que le hemos dado seguido de unos paréntesis. Éstos paréntesis es similar a un constructor, podemos configurar parámetros dentro de los paréntesis. A la parte de paréntesis se le conoce como **record header**. |
| 89 | + |
| 90 | +Copiamos los mismos que teníamos en Student.java: |
| 91 | + |
| 92 | +```java title="JavaStudent.java" |
| 93 | +public record JavaStudent(String id, String name, String dateOfBirth) { |
| 94 | +} |
17 | 95 | ``` |
18 | 96 |
|
19 | | -se construyen los objetos y se colocan referencias en las variables. |
| 97 | +**Hemos modificado todo el código anterior, por estas dos líneas. Teniendo en cuenta, que Record no soporta modificaciones, por tanto, no hay setters**. |
20 | 98 |
|
21 | | -**_null_** es un valor especial que significa "sin objeto". Se establece una variable de referencia a _null_ cuando no se refiere a ningún objeto. Las variables a menudo se asignan en nulas cuando se declaran: |
| 99 | +### Record header |
22 | 100 |
|
23 | | -```java |
24 | | - String str = null; |
25 | | - Persona p = null; |
| 101 | +A los parámetros que están dentro de la record header se les llama componentes. Por cada componente Java genera el siguiente código implícito: |
| 102 | + |
| 103 | ++ Un campo o atributo con el mismo nombre `private` y `final`. A este atributo se le conoce como **component field**. |
| 104 | ++ Un método de acceso público que tiene el mismo nombre y tipo del componente. Lo que sería un getter, pero no tiene ningún prefijo tipo _get_ o _is_ delante. |
| 105 | ++ Un constructor con los mismos argumentos y en el mismo orden descritos dentro de la cabecera de record. |
| 106 | ++ Java genera un método toString que imprime cada atributo formateado. |
| 107 | + |
| 108 | +### Constructores Record |
| 109 | + |
| 110 | +Si queremos generar un constructor, dentro de la clase record podemos hacer click botón derecho del ratón -> constructor: |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | +IntelliJ me ofrece tres opciones para generar un constructor: |
| 115 | + |
| 116 | + |
| 117 | + |
| 118 | +Los constructores de Record pueden ser de tres tipos: |
| 119 | + |
| 120 | +1. **Constructor canónico o largo** (canonical constructor): es el constructor implícito generado con los mismos componentes que hay en la cabecera. Se puede crear uno explícitamente, por lo que no se generará entonces el implícito. Si se declara uno explícito, se debe asignar a todos los campos un valor. |
| 121 | +2. **Constructor personalizado** (custom constructor): es un constructor sobrecargado. Su primera sentencia debe ser una llamada al canónico. |
| 122 | +3. **Constructor compacto o corto** (compact constructor): solo se utiliza en los records. Es una forma concisa de declarar un constructor canónico. |
| 123 | + |
| 124 | +```java title="JavaStudent.java" |
| 125 | +public record JavaStudent(String id, String name, String dateOfBirth) { |
| 126 | + //Canonical constructor |
| 127 | + //Hacer esto no tiene sentido, porque ya está implícito cuando poner los componentes en la cabecera |
| 128 | + public JavaStudent(String id, String name, String dateOfBirth) { |
| 129 | + this.id = id; |
| 130 | + this.name = name; |
| 131 | + this.dateOfBirth = dateOfBirth; |
| 132 | + } |
| 133 | + |
| 134 | + //Canonical constructor |
| 135 | + //En este caso, SI tiene sentido, porque queremos hacer algunas validaciones antes de asignar los valores |
| 136 | + public JavaStudent(String id, String name, String dateOfBirth) { |
| 137 | + this.id = (id.isEmpty()) ? "Unknown": id; |
| 138 | + this.name = name; |
| 139 | + this.dateOfBirth = dateOfBirth; |
| 140 | + } |
| 141 | +} |
26 | 142 | ``` |
27 | 143 |
|
28 | | -_str_ y _p_ todavía no son objetos, son variables que en un futuro pueden referenciar a objetos. |
| 144 | +#### Compact constructor |
| 145 | + |
| 146 | ++ No se pueden tener ambos constructores, el compact más el canónico explícito. |
| 147 | ++ El compact constructor se declara sin paréntesis y sin parámetros o argumentos. |
| 148 | ++ Tiene acceso a todos los argumentos o parámetros del constructor canónico, no confundir con los campos de la clase o variables de instancia de la clase. |
| 149 | ++ No se pueden hacer asignaciones a los campos de instancia de la clase en este constructor. |
| 150 | ++ Todas las asignaciones implícitas del constructor canónico ocurren después de la ejecución del código del constructor compacto. |
29 | 151 |
|
30 | | -Podemos asignar el valor null a cualquier variable de tipo referencia, ya sea un objeto, string, array, etc. |
| 152 | +Ejemplo: |
31 | 153 |
|
32 | | -Una variable de referencia a veces hace referencia a un objeto y otras veces no, y puede referirse a diferentes objetos en diferentes momentos. Por tanto, necesitamos una forma de decir que una variable ahora no se refiere a un objeto. Para ello, se le asigna un valor _null_ a la variable. |
| 154 | +```java |
| 155 | + //Compact constructor |
| 156 | + public JavaStudent { |
| 157 | + if (id.isEmpty()) id ="Unknown"; |
| 158 | + } |
| 159 | +``` |
33 | 160 |
|
34 | | - |
| 161 | +### Record immutable |
35 | 162 |
|
36 | | -El objeto Persona con el nombre de Patricia se destruirá eventualmente por el _garbage collector_ ya que no es referenciado por nadie. |
| 163 | +Con Record no tenemos setters, ni forma de modificar nuestros datos. Esto es debido a que, Record ha sido diseñado para ser inmutable, para que los datos se mantengan encapsulados y protegidos de mutaciones involuntarias. Por tanto, si necesitas modificar los datos de tu clase, nunca usaremos un Record, sino que crearemos un POJO como hicimos anteriormente. |
| 164 | + |
0 commit comments