Como desarrolladores e ingenieros de software, nuestro objetivo es siempre diseñar formas de obtener la máxima eficiencia y si necesitamos escribir menos código para ello, eso es una bendición.
En Java, un registro es un tipo especial de declaración de clase destinado a reducir el código repetitivo. Los registros de Java se introdujeron con la intención de ser utilizados como una forma rápida de crear clases de soporte de datos, es decir, las clases cuyo objetivo es simplemente contener datos y transportarlos entre módulos, también conocidos como POJO (Plain Old Java Objects) y DTO (Data Transferir Objetos). Record se introdujo en Java SE 14 como una función de vista previa, que es una función cuyo diseño, implementación y especificación están completos pero no es una adición permanente al lenguaje, lo que significa que la función puede existir o no en las versiones futuras. del idioma Java SE 15 amplía la función de vista previa con capacidades adicionales, como clases de registros locales.
Primero analicemos por qué necesitamos registros antes de implementarlos. Consideremos una ilustración para esto.
Ilustración:
Considere un Empleado de clase simple, cuyo objetivo es contener los datos de un empleado, como su ID y nombre, y actuar como un portador de datos para transferir entre módulos. Para crear una clase tan simple, necesitaría definir sus métodos constructor, getter y setter, y si desea usar el objeto con estructuras de datos como HashMap o imprimir el contenido de sus objetos como una string, tendríamos que invalidar métodos como equals(), hashCode() y toString().
Ejemplo
Java
// Java Program Illustrating Program Without usage of // Records // A sample Employee class class Employee { // Member variables of this class private String firstName; private String lastName; private int Id; // Constructor of this class public Employee(String firstName, String lastName, int Id) { // This keyword refers to current instance itself this.firstName = firstName; this.lastName = lastName; this.Id = Id; } // Setter and Getter methods // Setter-getter Method 1 public void setFirstName(String firstName) { this.firstName = firstName; } // Setter-getter Method 2 // to get the first name of employee public String getFirstName() { return firstName; } // Setter-getter Method 3 // To set the last name of employees public void setLastName(String lasstName) { // This keyword refers to current object itself this.lastName = lastName; } // Setter-getter Method 3 // To set the last name of employees public String getLastName() { return lastName; } // Setter-getter Method 4 // To set the last name of employees public void setId(int Id) { this.Id = Id; } // Setter-getter Method 5 // To set the last name of employees public int getId() { return Id; } // Setter-getter Method 6 public String toString() { // Return the attributes return "Employee [firstName=" + firstName + ", lastName=" + lastName + ", Id=" + Id + "]"; } // Method 7 // Overriding hashCode method @Override public int hashCode() { // Final variable final int prime = 31; int result = 1; result = prime * result + Id; result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); return result; } // Method 8 // Overriding equals method to // implement with data structures @Override public boolean equals(Object obj) { // This refers to current instance itself if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee)obj; if (Id != other.Id) return false; if (firstName == null) { if (other.firstName != null) return false; } else if (!firstName.equals(other.firstName)) return false; if (lastName == null) { if (other.lastName != null) return false; } else if (!lastName.equals(other.lastName)) return false; return true; } }
Nota: Son más de 100 líneas de código solo para crear una clase que contenga algunos datos.
Ahora veamos lo que se necesitaría para crear una clase similar usando Record para obtener su uso antes de discutir las propiedades de los registros que se detallan a continuación:
Algunas propiedades más de los registros
- Puede usar clases e interfaces anidadas dentro de un registro.
- También puede tener registros anidados, que implícitamente serán estáticos.
- Un registro puede implementar interfaces.
- Puede crear una clase de registro genérica.
- Es posible utilizar clases de registros locales (desde Java SE 15).
- Los registros son serializables.
Por muy tentador que sea usar registros para objetos portadores de datos, los registros siguen siendo una función de vista previa en Java. Además, dado que están destinados a ser utilizados solo como portadores de datos, definir nuestros propios métodos de acceso y otros métodos de instancia desafiaría el propósito. Los registros se pueden usar para reducir el trabajo realizado por el desarrollador, pero internamente la diferencia de rendimiento entre un registro y una clase no es tan amplia.
public record Employee(int id, String firstName, String lastName) {}
¡Eso es todo! Solo 2 líneas de código, eso es todo lo que necesita para implementar esas 80 líneas de código usando Record. Para saber cómo implementa Java esta función, primero aprenderemos a configurarla nosotros mismos. Ahora analicemos los pasos con ayudas visuales que demuestran los registros de Java. Dado que Records es una característica de Java SE 14, necesitaríamos JDK 14 en nuestra máquina. Descargue Oracle JDK 14 de este archivo para su máquina. Después de descargar e instalar JDK-14 en la carpeta Java junto con cualquier otra versión de Java, siga los pasos a continuación.
Nota : Para este tutorial se utiliza Eclipse IDE.
Pasos para configurar registros java
Paso 1: Cree un nuevo proyecto Java y seleccione JavaSE-14 como entorno de ejecución.
Paso 2: si es la primera vez que usa JDK-14, habrá algunos pasos más que deberá seguir para configurar los registros para que funcionen. Es posible que vea este tipo de marca de excepción en la carpeta de su proyecto.
Paso 3: Para arreglar eso, en la parte superior, ve a Ventana -> Preferencias .
Paso 4: en la ventana Preferencias, haga clic en JRE instalados y luego haga clic en Agregar como se muestra a continuación:
Paso 5: Ahora, en la ventana Agregar JRE que se abre, seleccione VM estándar y haga clic en Siguiente. Verá una nueva ventana abierta para seleccionar un JRE, ahora haga clic en Directorio y navegue hasta donde está instalado su jdk-14 y seleccione esa carpeta. Haga clic en Finalizar .
Paso 6: marque el JDK-14 que acaba de agregar y aplíquelo .
Paso 7: Aún no hemos terminado. Dado que los registros son una función de vista previa, debemos habilitarlos para que la usen. En la ventana del Explorador de proyectos en el lado izquierdo, seleccione su proyecto y haga clic con el botón derecho y vaya a sus Propiedades .
Paso 8: En la ventana que se abre, a la derecha, de las diversas opciones, seleccione Compilador de Java. Después de eso, en el lado izquierdo, desmarque las configuraciones marcadas con flechas rojas en la imagen y marque la configuración resaltada con verde. Hacer eso habilitará las funciones de vista previa.
Paso 9: después de hacer clic en Aplicar y cerrar, verá un mensaje que le preguntará si desea reconstruir el proyecto. Seleccione Sí .
Implementación:
Después de configurar el entorno, ahora podemos proceder a escribir el código para los registros.
Los registros de codificación se declaran escribiendo registros en lugar de clases en la declaración de clase. Al definir un registro, todos los campos de instancia se escriben como parámetros. El compilador de Java genera el constructor, los métodos getter, toString(), equals() y hashCode() durante el tiempo de compilación. Una cosa a tener en cuenta aquí es que los registros no proporcionan métodos de establecimiento, ya que se espera que el valor de las variables de instancia se proporcione al crear el objeto.
// A simple Employee class to be used as a DTO public record Employee(int id, String firstName, String lastName) { }
Ejemplo 1
// Creating Employee object and showcasing its use cases // Main class class GFG { // Main driver method public static void main(String args[]) { // Creating object with default constructor Employee e1 = new Employee(1001, "Derok", "Dranf"); // Auto generated getter methods System.out.println(e1.id() + " " + e1.firstName() + " " + e1.lastName()); // Auto-generated toString() method System.out.println(e1.toString()); } }
Producción:
1001 Derok Dranf Employee[id=1001, firstName=Derok, lastName=Dranf]
Notaremos que los métodos getter no son similares en la convención de nomenclatura a los métodos getter normales que se crean (p. ej., getFirstName()), sino que simplemente se indican con el nombre del campo (p. ej., firstName()). Ahora, ampliemos nuestro ejemplo anterior para probar estas funcionalidades.
Eso no es todo lo que un disco puede hacer. Los registros también nos brindan la capacidad de:
- Crear nuestros propios constructores. En los registros, puede crear un constructor parametrizado, que llama al constructor predeterminado con los parámetros proporcionados dentro de su cuerpo. También puede crear constructores compactos que son similares a los constructores predeterminados con la diferencia de que puede agregar alguna funcionalidad adicional, como comprobaciones dentro del cuerpo del constructor.
- Crear métodos de instancia. Como cualquier otra clase, puede crear y llamar a métodos de instancia para la clase de registro.
- Crear campos estáticos. Los registros nos restringen a escribir las variables de instancia solo como parámetros, pero permiten el uso de variables estáticas y métodos estáticos.
Ejemplo 1
// Java Program Illustrating a Record class // defining constructors, instance methods // and static fields // Record class public record Employee(int id, String firstName, String lastName) { // Instance fields need to be present in the record's // parameters but record can define static fields. static int empToken; // Constructor 1 of this class // Compact Constructor public Employee { if (id < 100) { throw new IllegalArgumentException( "Employee Id cannot be below 100."); } if (firstName.length() < 2) { throw new IllegalArgumentException( "First name must be 2 characters or more."); } } // Constructor 2 of this class // Alternative Constructor public Employee(int id, String firstName) { this(id, firstName, null); } // Instance methods public void getFullName() { if (lastName == null) System.out.println(firstName()); else System.out.println(firstName() + " " + lastName()); } // Static methods public static int generateEmployeeToken() { return ++empToken; } }
Ejemplo 2
Java
// Java Program to Illustrate Record's functionalities // Main class class GFG { // Main driver method public static void main(String args[]) { // Creating object with default constructor Employee e1 = new Employee(1001, "Derok", "Dranf"); // auto generated getter methods System.out.println(e1.id() + " " + e1.firstName() + " " + e1.lastName()); // Auto-generated toString() method System.out.println(e1.toString()); // Creating object with parameterized constructor Employee e2 = new Employee(1002, "Seren"); // Using instance methods e2.getFullName(); // Using static methods System.out.println("Employee " + e2.id() + " Token = " + e2.generateEmployeeToken()); // Using the equals() method System.out.print("Is e1 equal to e2: " + e1.equals(e2)); } }
Producción:
1001 Derok Dranf Employee[id=1001, firstName=Derok, lastName=Dranf] Seren Employee 1002 Token = 1 Is e1 equal to e2: false
Geek, ¿alguna vez te has preguntado qué magia hace el Compilador?
Como se discutió anteriormente, el registro es solo una declaración especial de una clase e internamente el compilador la convierte en una clase normal con algunas restricciones, lo que la hace diferente de las clases típicas. Cuando el compilador de Java compila el archivo Java al código de bytes, el archivo .class producido contiene la declaración extendida de la clase de registro. Al mirar ese archivo, podemos obtener más información sobre los registros. El código de bytes producido para el registro de empleado que creamos anteriormente es el siguiente:
public final class Employee extends java.lang.Record { private final int id; private final java.lang.String firstName; private final java.lang.String lastName; static int empToken; public Employee(int id, java.lang.String firstName, java.lang.String lastName) { /* compiled code */ } public Employee(int id, java.lang.String firstName) { /* compiled code */ } public void getFullName() { /* compiled code */ } public static int generateEmployeeToken() { /* compiled code */ } public int id() { /* compiled code */ } public java.lang.String firstName() { /* compiled code */ } public java.lang.String lastName() { /* compiled code */ } public java.lang.String toString() { /* compiled code */ } public final int hashCode() { /* compiled code */ } public final boolean equals(java.lang.Object o) { /* compiled code */ } }
Conclusión: si nos tomamos un tiempo para observar el código de bytes, notará lo siguiente:
- El registro ha sido reemplazado por clase .
- La clase y sus miembros de datos se han declarado como finales . Esto implica que esta clase no se puede extender, es decir, no se puede heredar y también es inmutable.
- La clase extiende java.lang.Record . Esto significa que todos los registros son una subclase de Registro definido en el paquete java.lang.
- Hay un constructor predeterminado y un constructor parametrizado. Notará que no hay una declaración separada para el constructor compacto que definimos. Esto se debe a que el constructor compacto no genera un constructor independiente sino que agrega su código al comienzo del cuerpo del constructor predeterminado.
- Los métodos de instancia y estáticos se declaran como estaban.
- El compilador ha generado automáticamente los métodos toString(), hashCode() y equals().
Publicación traducida automáticamente
Artículo escrito por yuvrajjoshi31 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA