Bienvenidos a otro capítulo de este Curso Gratis de Java para Hackers – Novedades en Java. Comparte este articulo y síguenos para recibir más capítulos, guías y cursos gratis.

Tabla de contenidos

¿Te gustaría enterarte de cuando lanzamos descuentos y nuevos cursos?

Veremos las actualizaciones de Java en sus versiones 8, 16 y 24 (Próximamente) 

JAVA 8 nuevas funciones

es una versión importante del desarrollo del lenguaje de programación JAVA. Su versión inicial se lanzó el 18 de marzo de 2014. Con el lanzamiento de Java 8, Java proporcionó soporte para programación funcional, nuevo motor JavaScript, nuevas API para manipulación de fecha y hora, nueva API de transmisión, etc. A continuación, se muestra la lista de nuevas funciones admitidas en Java 8:

Expresiones lambda

La expresión lambda es una de las características más importantes introducidas en Java. Una expresión lambda facilita la programación funcional en Java. Una expresión lambda funciona según el principio de interfaz funcional. Una interfaz funcional es una interfaz con un solo método para implementar. Una expresión lambda proporciona una implementación del método de interfaz funcional.

La expresión Lambda simplifica mucho la programación funcional y hace que el código sea legible sin ningún código repetitivo. Una expresión lambda puede inferir el tipo de parámetro utilizado y puede devolver un valor sin una palabra clave de retorno. En el caso del método simple de una sola instrucción, incluso se pueden eliminar las llaves.

Ejemplo: uso de expresiones Lambda

El siguiente ejemplo muestra el uso de la expresión lambda. Una expresión lambda funciona mejor con una interfaz funcional, una interfaz con un único método abstracto. Hemos definido una calculadora de interfaz con operación de método único, que puede aceptar dos parámetros y devolver un valor.

En el método principal, implementamos la interfaz de la Calculadora usando primero una función anónima y luego usando una expresión lambda. Se llama al método operar() para imprimir el resultado en ambos casos y se imprimen los resultados.

package com.alvarocalc;

public class Tester {

   public static void main(String[] args) {
      // Interface implementation using anonymous class
      Calculator sum = new Calculator() {
         @Override
         public int operate(int a, int b) {
            return a + b;
         }
      };
      int result = sum.operate(2,3);
      System.out.println(result);	   

      // Interface implementation using lambda expression
      Calculator sum1 = (a,b) -> a + b;
      result = sum1.operate(2,3);
      System.out.println(result);
   }  

   interface Calculator {
      int operate(int a, int b);
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

5
5

Referencias de métodos

La referencia a métodos es una forma breve y concisa de llamar a métodos, métodos estáticos e incluso constructores sin una sintaxis extensa. Las referencias a métodos ayudan a señalar métodos por sus nombres incluso sin especificar los argumentos. Los argumentos se pasan mediante la expresión lambda. La referencia de un método se describe utilizando el símbolo «::».

Se puede hacer referencia a un método estático utilizando la siguiente sintaxis:

<<class-name>>::methodName

Se puede hacer referencia a un método de instancia utilizando la siguiente sintaxis:

<<object-name>>::methodName

Podemos invocar al constructor usando la siguiente sintaxis:

<<class-name>>::new

Ejemplo: uso de referencias de métodos

En este ejemplo, hemos utilizado un método estático de comparación y un método de instancia compareTo para ordenar dos listas de matrices de números enteros. Hemos utilizado referencias de métodos para representar métodos estáticos y de instancia.

package com.achirou;

import java.util.Arrays;
import java.util.List;

public class Tester {
   public static void main(String args[]) {
      List<Integer> numbers = Arrays.asList(1,2,4,9,8,7,3);
      System.out.println("Sorted using static method reference");
      // Use static method compare
      numbers = numbers.stream().sorted(Integer::compare).toList();
      System.out.println(numbers);

      numbers = Arrays.asList(1,2,4,9,8,7,3);
      System.out.println("Sorted using instance method reference" );
      // Use instance method compareTo
      numbers = numbers.stream().sorted(Integer::compareTo).toList();

      System.out.println(numbers);		
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Sorted using static method reference
[1, 2, 3, 4, 7, 8, 9]

Sorted using instance method reference
[1, 2, 3, 4, 7, 8, 9]

Métodos predeterminados

Antes de Java 8, una interfaz sólo podía tener métodos abstractos. Con Java 8, se introdujeron las expresiones lambda. Ahora, para la compatibilidad con versiones anteriores, se agregó la capacidad del método predeterminado para que las interfaces antiguas puedan aprovechar la expresión lambda sin modificar sus implementaciones.

Por ejemplo, las interfaces Lista o Colección no tienen una declaración de método ‘forEach’. Por lo tanto, agregar dicho método simplemente romperá las implementaciones del marco de recopilación. Java 8 introduce el método predeterminado para que la interfaz Lista/Colección pueda tener una implementación predeterminada del método forEach, y la clase que implementa estas interfaces no necesita implementar la misma.

Sintaxis

La siguiente es la sintaxis del método predeterminado en la interfaz en Java:

public interface vehicle {
   default void message() {
      System.out.println("I am a vehicle!");
   }
}

Ejemplo: uso del método predeterminado

En este ejemplo, hemos creado una interfaz con un método predeterminado. En una clase de implementación, este mensaje no se implementa y se usa para imprimir un mensaje.

package com.achirou;

interface vehicle {
   // default method must have an implementation
   default void message() {
      System.out.println("I am a vehicle!");
   }
}

// implementing class need not to implement the default method
// of an interface.
public class Tester implements vehicle {
   public static void main(String args[]) {
      Tester tester = new Tester();
      // implementing class can access the default method as its own method
      tester.message(); 
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

I am a vehicle!

API de transmisión

Stream API es una nueva capa abstracta introducida en Java 8 para procesar datos de forma declarativa. Una secuencia representa una secuencia de elementos. y proporciona un conjunto de elementos de un tipo específico de forma secuencial. Una secuencia obtiene/calcula elementos a pedido. Nunca almacena los elementos.

Stream admite operaciones agregadas como filtrar, asignar, limitar, reducir, buscar, comparar, etc., y puede realizar iteraciones internamente sobre los elementos fuente proporcionados, a diferencia de Colecciones, donde se requiere una iteración explícita.

Sintaxis

La siguiente es la sintaxis genérica para usar una secuencia.

<<collection-instance>>.stream().<<non-terminal-operation()>>.<<non-terminal-operation()>>.<<terminal-operation()>>

Ejemplo: uso de Stream

En este ejemplo, hemos creado una lista de cadenas donde algunas entradas están vacías. Ahora, usando la API de transmisión, filtramos las cadenas vacías y las contamos.

package com.achirou;

import java.util.Arrays;
import java.util.List;

public class Tester {
   public static void main(String args[]) {
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

      // get stream from list using stream() method
      // then apply filter
      // lastly count the result of filter
      long count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Empty Strings: 2

Clase Opcional

La característica de clase opcional se introdujo en Java 8 para manejar escenarios de excepción de puntero nulo mediante programación, para hacer que los programas sean más concisos y menos propensos a errores. Se produce una excepción de puntero nulo siempre que se utiliza una referencia de objeto nulo para obtener valor de él o para invocar su método. A medida que aumenta el tamaño del programa, resulta muy tedioso manejar todos los casos en los que puede ocurrir una excepción de puntero nulo.

La instancia de clase opcional proporciona un contenedor sobre el objeto con muchos métodos de utilidad, como obtener el valor alternativo si el valor subyacente es nulo, verificar si la referencia del objeto es nula, etc.

Ejemplo: uso de una clase opcional

En este ejemplo, hemos creado dos instancias de clase Opcional usando el método oofNullable() que permite pasar el objeto subyacente como nulo y luego recuperamos el valor usando el método orElse(), que devuelve un valor predeterminado si el objeto subyacente es nulo.

package com.achirou;

import java.util.Optional;

public class Tester {
   public static void main(String args[]) {
      // case 1: Optional is having null as underlying value
      Optional<Integer> valueOptional = Optional.ofNullable(null);

      // case 2:  Optional is having not null as underlying value
      Optional<Integer> valueOptional1 = Optional.ofNullable(Integer.valueOf(10));

      // orElse will return -1 being default value
      Integer value = valueOptional.orElse(Integer.valueOf(-1));

      System.out.println(value);

      //  orElse will return the underlying value
      Integer value1 = valueOptional1.orElse(Integer.valueOf(-1));

      System.out.println(value1);
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

-1
10

Nueva API de fecha y hora

Java 8 introdujo una nueva API de fecha y hora que es segura para subprocesos, está lista para zonas y tiene múltiples métodos directos para manejar operaciones de fecha. La API de fecha y hora anterior no era segura para subprocesos y podían surgir problemas de concurrencia al trabajar con fechas. Las nuevas API de fecha y hora utilizan construcciones inmutables y ningún método de establecimiento, lo que hace que la API sea más segura. La nueva API está diseñada teniendo en cuenta los requisitos específicos de la zona y el dominio.

Java 8 introduce una nueva API de fecha y hora en el paquete java.time. A continuación se muestran algunas de las clases importantes introducidas en el paquete java.time.

  • Local : API de fecha y hora simplificada sin complejidad en el manejo de la zona horaria.
  • Zonificado : API de fecha y hora especializada para tratar con varias zonas horarias.

Ejemplo: uso de API de fecha y hora

En este ejemplo, hemos creado dos instancias de clase Opcional usando el método oofNullable() que permite pasar el objeto subyacente como nulo y luego recuperamos el valor usando el método orElse(), que devuelve un valor predeterminado si el objeto subyacente es nulo.

package com.achirou;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZonedDateTime;

public class Tester {
   public static void main(String args[]) {
      // Get the current date and time
      LocalDateTime currentTime = LocalDateTime.now();
      System.out.println("Current DateTime: " + currentTime);

      LocalDate date1 = currentTime.toLocalDate();
      System.out.println("date1: " + date1);

      Month month = currentTime.getMonth();
      int day = currentTime.getDayOfMonth();
      int seconds = currentTime.getSecond();

      System.out.println("Month: " + month +", day: " + day +", seconds: " + seconds);

      ZonedDateTime date2 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
      System.out.println("date2: " + date2);
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Current DateTime: 2024-03-07T10:29:15.650806
date1: 2024-03-07
Month: MARCH, day: 7, seconds: 15
date2: 2007-12-03T09:45:30+05:00[Asia/Karachi]

Motor JavaScript Nashorn

Nashorn , un motor Javascript muy potente y eficiente, se presenta como reemplazo del motor JavaScript existente, Rhino. Se promociona que el motor Nashorn es de 2 a 10 veces más rápido, ya que puede compilar directamente el código JavaScript en código de bytes. El motor Nashorn permite ejecutar código JavaScript en un archivo Java e incluso podemos ejecutar código Java dentro de un fragmento de código JavaScript.

Con el motor Nashorn, se introdujo una herramienta de línea de comandos jjs para ejecutar javascript en las herramientas de línea de comandos.

Ejecute JavaScript directamente en el símbolo del sistema

Abra la consola, escriba jjs y presione el botón Enter. La herramienta jjs abrirá una sesión interactiva. Una vez abierta la sesión jjs, podemos ejecutar un código javascript. Una vez hecho esto, escriba quit() y presione el botón Intro para salir de la sesión interactiva de jjs y volver al símbolo del sistema.

Ejemplo

C:\JAVA>jjs

jjs> print(«Hello, World!»)

Hello, World!

jjs> quit()

>>

C:\JAVA>

Ejemplo: uso de código Javascript dentro del código Java

Java tiene una clase ScriptEngineManager desde Java 6, que se utiliza en este ejemplo para cargar el motor javascript como instancia de ScriptEngine. Una vez que el motor está cargado en el código Java, podemos llamar al método eval() para evaluar un código JavaScript en Java. Incluso podemos usar variables de Java en un fragmento de código de JavaScript.

package com.achirou;

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

public class Tester {

   public static void main(String args[]) {
      // create the script engine manager   
      ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
      // load the Nashorn javascript engine
      ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
		
      String message = "This is a message";
      String expression = "10 + 2";
      Integer result = null;
      
      try {
         // call the javascript function, pass a java variable	  
         nashorn.eval("print('" + message + "')");
         // call the javascript function and get the result back in java
         result = (Integer) nashorn.eval(expression);
         
      } catch(ScriptException e) {
         System.out.println("Error executing script: "+ e.getMessage());
      }
      System.out.println(result.toString());
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

This is a message
12

El motor Nashorn quedó obsoleto en Java 11 y se eliminó en Java 15 y es reemplazado por el motor JavaScript GraalVM.

Versiones de Java

1 JDK Beta 1995

Versión borrador inicial

2 JDK 1.0 23 de enero de 1996

Una variante estable JDK 1.0.2 se denominó JDK 1

3 JDK 1.1 19 de febrero de 1997

En esta versión se agregaron funciones importantes como JavaBeans , RMI , JDBC y clases internas .

4 JDK 1.2 8 de diciembre de 1998

Swing , el compilador JIT, los módulos Java y las colecciones se introdujeron en JAVA y esta versión fue un gran éxito.

5 JDK 1.3 8 de mayo de 2000

Se agregaron HotSpot JVM , JNDI, JPDA, JavaSound y soporte para clases de proxy sintético.

6 JDK 1.4 6 de febrero de 2002

Se agregó API de E/S de imagen para crear/leer imágenes JPEG/PNG. El analizador XML integrado y el procesador XSLT (JAXP) y la API de Preferencias fueron otras actualizaciones importantes.

7 JDK 1.5 o J2SE 5 30 de septiembre de 2004

Se agregaron varias características nuevas al lenguaje como foreach, var-args, generics, etc.

8 JAVASE6 11 de diciembre de 2006

La notación se eliminó a SE y se realizaron actualizaciones a JAXB 2.0, compatibilidad con JSR 269 y compatibilidad con JDBC 4.0.

9  JAVASE7 7 de julio de 2011

Se agregó soporte para lenguajes dinámicos a JVM. Otras mejoras incluyeron cadenas en la caja del interruptor, punteros comprimidos de 64 bits, etc.

10 JAVASE 8 18 de marzo de 2014

Se agregó soporte para programación funcional. Expresiones lambda, flujos, métodos predeterminados, nuevas API de fecha y hora introducidas.

11 JAVA SE 9 21 de septiembre de 2017

Se introdujo un sistema de módulos que se puede aplicar a la plataforma JVM.

12 JAVASE10 20 de marzo de 2018

Se agregaron extensiones de etiquetas de idioma Unicode. Se introdujeron certificados raíz, apretones de manos locales de subprocesos, soporte para asignación de montón en dispositivos de memoria alternativos, etc.

13 JAVASE11 5 de septiembre de 2018

Constantes dinámicas de archivos de clase, Epsilon, un recolector de basura no operativo, soporte de variables locales en parámetros lambda, soporte agregado de perfiles de montón de bajo costo.

14 JAVASE12 19 de marzo de 2019

Recolector de basura experimental, Shenandoah: se agregó un recolector de basura con tiempo de pausa bajo, Microbenchmark Suite y API JVM Constants.

15 JAVA SE 13 17 de septiembre de 2019

Característica agregada: bloques de texto (cadenas multilínea), apretones de manos locales de subprocesos mejorados.

16 JAVASE14 17 de marzo de 2020

Característica agregada: registros, un nuevo tipo de clase para modelado, coincidencia de patrones, por ejemplo, manejo intuitivo de excepciones de puntero nulo.

17 JAVASE15 15 de septiembre de 2020

Característica agregada: clases selladas, clases ocultas, función externa y API de memoria (incubadora).

18 JAVA SE 16 16 de marzo de 2021

Característica agregada como vista previa: registros, coincidencia de patrones para conmutador, canal de socket de dominio Unix (incubadora), etc.

19 JAVA SE 17 14 de septiembre de 2021

Característica agregada como finalizada: clases selladas, coincidencia de patrones, por ejemplo, encapsulación sólida de elementos internos de JDK de forma predeterminada. Nueva canalización de renderizado de macOS, etc.

20 JAVA SE 18 22 de marzo de 2022

Característica agregada: UTF-8 de forma predeterminada, fragmentos de código en la documentación de la API de Java, API de vectores (tercera incubadora), función externa, API de memoria (segunda incubadora), etc.

21 JAVA SE 19 20 de septiembre de 2022

Característica agregada: patrón de registro, API vectorial (cuarta incubadora), simultaneidad estructurada (incubadora), etc.

22 JAVASE20 21 de marzo de 2023

Característica agregada: valores de alcance (incubadora), patrones de registro (segunda vista previa), coincidencia de patrones para conmutador (cuarta vista previa), función externa y API de memoria (segunda vista previa), etc.

22 JAVA SE 21 19 de septiembre de 2023

Característica agregada: plantillas de cadenas (vista previa), colecciones secuenciadas, ZGC generacional, patrones de registro, coincidencia de patrones para conmutadores, etc.

Tutorial de Java 16

Java 16 introdujo algunas características específicas del lenguaje en el modo de vista previa de Java y múltiples mejoras de JVM. Este es un tutorial introductorio que explica las funciones básicas y avanzadas de Java 16 y su uso de una manera sencilla e intuitiva.

Java 16 es una versión de funciones importante y ha traído muchos cambios específicos de JVM y cambios específicos de lenguaje a JAVA. Siguió la cadencia de lanzamiento de Java introducida desde Java 10 en adelante y se lanzó en marzo de 2021, solo seis meses después del lanzamiento de Java 15. Java 16 es una versión que no es LTS.

Nuevas características

A continuación se detallan las principales características nuevas que se introducen en Java 16.

  • JEP 338 – API de vectores (incubadora) : se introdujeron nuevas API de vectores que permiten a los desarrolladores realizar operaciones vectoriales de forma explícita.
  • JEP 347: habilitar funciones del lenguaje C++ 14 : las funciones de C++ 14 se pueden usar en el código fuente de C++ con JDK 16.
  • JEP 357, JEP 369 – Migración de Mercurial a Git/GitHub – El código fuente OpenJDK se mueve de Mercurial a Git/GitHub
  • JEP 376 – ZGC – Procesamiento concurrente de pila de subprocesos : Z Garbage Collector mejoró al mover su procesamiento de pila de subprocesos desde puntos seguros a la fase concurrente.
  • JEP 380: canales de socket de dominio Unix : SocketChannel y ServerSocketChannel ahora admiten sockets de dominio Unix.
  • JEP 386 – Puerto Alpine Linux : ahora JDK está disponible para Alpine Linux y otras distribuciones de Linux que utilizan la implementación musl.
  • JEP 387 – Elastic Metaspace – La gestión de la memoria del metaespacio se mejora al devolver rápidamente los metadatos de clase HotSpot o la memoria del metaespacio no utilizados al sistema operativo, reduce la huella del metaespacio y simplifica el código del metaespacio.

Mas características nuevas son:

  • JEP 388 – Puerto Windows/AArch64 : ahora JDK puede ejecutarse en AArch64, en un servidor de hardware ARM o en computadoras portátiles basadas en ARM.
  • JEP 389 – API de enlace externo (incubadora) : el código Java se puede llamar mediante C/C++ o viceversa utilizando una nueva API que reemplaza a JNI.
  • JEP 390: Advertencias para clases basadas en valores : se generan advertencias en caso de que las clases basadas en valores se sincronicen mediante sincronización.
  • JEP 392 – Herramienta de empaquetado : jpackage ahora es una característica estándar en lugar de una incubadora.
  • JEP 393 – API de acceso a memoria externa (tercera incubadora) : mejoras menores a la API de acceso a memoria externa.
  • JEP 394 – Coincidencia de patrones por ejemplo de – La coincidencia de patrones por ejemplo de ahora es una característica estándar.
  • JEP 395 – Registros : los registros ahora son una característica estándar.
  • JEP 396 – Encapsular fuertemente los componentes internos del JDK de forma predeterminada : el modo predeterminado de la opción –illegal-access ahora es denegar. Antes era un permiso.
  • JEP 397 – Clases selladas (segunda vista previa) : mejoras menores a las clases selladas.

Java 16 mejoró numerosas API con nuevos métodos y opciones. Veremos estos cambios en los próximos capítulos.

Java: clases e interfaces selladas

En Java 15 se introdujo una clase sellada como característica de vista previa que proporciona un control detallado sobre la herencia . Java 16 proporciona algunas mejoras menores y mantiene esta función como versión preliminar. Con Java 17, clase sellada e interfaz son características estándar.

Se agrega una característica de clase/interfaz sellada a Java para proporcionar a los desarrolladores un control detallado sobre la herencia. Una clase sellada puede definir los subtipos a los que se les permite extenderla, mientras que otras clases no pueden extenderla.

Los siguientes son puntos destacados a considerar para una clase sellada:

  • Una clase sellada se declara mediante una palabra clave sellada.
  • Las clases selladas permiten declarar qué clase puede ser un subtipo utilizando la palabra clave permisos.
  • Una clase que extiende la clase sellada debe declararse como sellada, no sellada o final.
  • Las clases selladas ayudan a crear una jerarquía finita y determinable de clases en herencia.

Interfaz sellada

Una interfaz se puede marcar como interfaz sellada usando la palabra clave sellada y luego usando las palabras clave de permisos , podemos agregar las interfaces que pueden ampliar esta interfaz.

public sealed interface Person permits Employee, Manager {

}

Ejemplo de interfaz sellada

En este ejemplo, hemos creado una interfaz sellada Persona que permite que las interfaces de Empleado y Gerente la extiendan. Las interfaces de empleado y gerente tienen diferentes métodos para obtener la identificación de una persona.

Ahora, para obtener la identificación de una persona, usamos el operador instancia de para verificar que una instancia sea de Empleado o Gerente y obtener la identificación correspondiente. Por lo tanto, podemos ver que conocer las interfaces permitidas de antemano ayuda en el desarrollo de tales escenarios.

package com. achirou;

public class Tester {
   public static void main(String[] args) {
      // create an instance of Manager
      Person manager = new CorpManager(23, "Robert");

      // get the id
      System.out.println("Id: " + getId(manager));
   }
   public static int getId(Person person) {
      // check if person is employee then return employee id
      if (person instanceof Employee) {
         return ((Employee) person).getEmployeeId();
      } 
      // if person is manager then return manager id
      else if (person instanceof Manager) {
         return ((Manager) person).getManagerId();
      }
      return -1;
   }
}

// a sealed interface Person which is to be inherited by Employee
// and Manager interfaces
sealed interface Person permits Employee, Manager {
   String getName();
}

// Employee and Manager interfaces have to extend Person and can be sealed or non-sealed
non-sealed interface Employee extends Person {
   int getEmployeeId();
}

non-sealed interface Manager extends Person {
   int getManagerId();
}

class CorpEmployee implements Employee {
   String name;
   int id;

   public CorpEmployee(int id,String name) {
      this.name = name;
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public int getEmployeeId() {
      return id;
   }		
}

class CorpManager implements Manager {
   String name;
   int id;
   public CorpManager(int id,String name) {
      this.name = name;
      this.id = id;
   }
   public String getName() {
      return name;
   }

   public int getManagerId() {
      return id;
   }		
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Id: 23

Clase sellada

De manera similar a la interfaz sellada, una clase también se puede marcar como clase sellada usando la palabra clave sellada y luego usando las palabras clave de permisos, podemos agregar las subclases que pueden extender esta clase.

public abstract sealed class Person permits Employee, Manager {

}

Una subclase necesita tener un modificador como sellado/final o no sellado.

public final class Manager extends Person {

}

Una subclase sin sellado está abierta para que todas las clases la extiendan.

public non-sealed class Employee extends Person {

}

Restricciones

Existen pocas restricciones en el uso de clases selladas que debemos tener en cuenta al extender una clase sellada.

  • La subclase permitida debe ser parte del mismo módulo que la clase sellada.
  • La subclase permitida tiene que ampliar la clase sellada.
  • Una subclase permitida tiene que utilizar cualquiera de los modificadores finales, sellados o no sellados.

Ejemplo de clase sellada

En este ejemplo, hemos creado una clase abstracta sellada Persona que permite que las clases Empleado y Gerente la extiendan. Las clases de Empleado y Gerente tienen diferentes métodos para obtener la identificación de una persona. Ahora, para obtener la identificación de una persona, utilizamos el operador instancia de para verificar que una instancia sea de Empleado o Gerente y obtener la identificación correspondiente. Por lo tanto, podemos ver que conocer las subclases permitidas por adelantado ayuda en el desarrollo de tales escenarios.

package com.achirou;

public class Tester {
   public static void main(String[] args) {
      // create an instance of Manager
      Person manager = new Manager(23, "Robert");

      // get the id
      System.out.println("Id: " + getId(manager));
   }
   public static int getId(Person person) {
      // check if person is employee then return employee id
      if (person instanceof Employee) {
         return ((Employee) person).getEmployeeId();
      } 
      // if person is manager then return manager id
      else if (person instanceof Manager) {
         return ((Manager) person).getManagerId();
      }
      return -1;
   }
}

// a sealed class Person which is to be inherited by Employee
// and Manager classes
abstract sealed class Person permits Employee, Manager {
   String name;
   String getName() {
      return name;
   }
}

// Employee class has to extend Person and should have a modifier
final class Employee extends Person {
   String name;
   int id;
   Employee(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getEmployeeId() {
      return id;
   }
}

// We can mark a sub-class as non-sealed, so that it can be extended if required
non-sealed class Manager extends Person {
   int id;
   Manager(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getManagerId() {
      return id;
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Id: 23

Java 16: coincidencia de patrones, por ejemplo

Java 14 introduce el operador instancia de para tener un patrón de prueba de tipo como característica de vista previa. El patrón de prueba de tipo tiene un predicado para especificar un tipo con una única variable de enlace. También sigue siendo una función de vista previa en Java 15. Con Java 16, esta característica ahora forma parte de la entrega estándar.

Sintaxis

if (person instanceof Employee e) {
   return e.getEmployeeId();
}

Ejemplo

Considere el siguiente ejemplo:

ApiTester.java

public class APITester {
   public static void main(String[] args) {
      Person manager = new Manager(23, «Robert»);
      manager.name = «Robert»;
      System.out.println(getId(manager));
   }
   public static int getId(Person person) {
      if (person instanceof Employee e) {
         return e.getEmployeeId();
      }
      else if (person instanceof Manager m) {
         return m.getManagerId();
      }
      return -1;
   }
}
abstract class Person {
   String name;
   String getName() {
      return name;
   }
}
final class Employee extends Person {
   String name;
   int id;
   Employee(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getEmployeeId() {
      return id;
   }
}
final class Manager extends Person {
   int id;
   Manager(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getManagerId() {
      return id;
   }
}

Compilar y ejecutar el programa

$javac APITester.java
$java APITester

Producción

23

Java 16: advertencia para clases basadas en valores

Algunas clases, como java.util.Optional y java.time.LocalDateTime, se basan en valores. Estas instancias de una clase basada en valores son definitivas e inmutables. Estas clases tienen la anotación @jdk.internal.ValueBased y Java 16 ahora genera advertencias en tiempo de compilación en caso de que dichas clases se sincronicen mediante la palabra clave sincronizada. Las clases contenedoras se basan en valores. Por ejemplo, la clase Double se basa en un valor.

Ejemplo

package java.lang;
@jdk.internal.ValueBased
public final class Double extends Number
   implements Comparable<Double>, Constable, ConstantDesc {
   //…
}

Considere el siguiente ejemplo:

ApiTester.java

Ejemplo

public class APITester {
   public static void main(String[] args) {
      Double d = 10.0;
      synchronized (d) {
         System.out.println(d);                        
      }
   }
}

Compilar y ejecutar el programa

$javac APITester.java

Producción

APITester.java:4: warning: [synchronization] attempt to synchronize on an instance of a value-based class
   synchronized (d) {
   ^
1 warning

Java – Registro

En Java 14, se introdujo un interesante registro de funciones como función de vista previa. La función de registro ayuda a crear objetos de datos inmutables. En la versión Java 15, los tipos de registros se mejoraron aún más. En Java 14 y 15, para utilizar un registro , se debe pasar un indicador –enable-preview. A partir de Java 16, este indicador no es necesario ya que el registro es una parte estándar de JDK.

Propósito de un registro Java

El objetivo principal de un registro es crear un objeto de datos o un POJO que se utiliza para transportar datos en el flujo del programa de aplicación. En un programa de múltiples niveles, los objetos de Dominio/Modelo almacenan los datos capturados de la fuente de datos y luego estos objetos de modelo se pasan a la capa de aplicación/UI para procesar los datos y viceversa, donde UI/Aplicación almacena datos en objetos de datos y luego pase estos objetos a la capa de datos para completar las fuentes de datos.

Como estos objetos de datos contienen muchos campos, los desarrolladores deben escribir muchos métodos setter/getter, constructores parametrizados , métodos iguales anulados y métodos de código hash. En tal escenario, el registro viene al rescate ya que proporciona la mayor parte del código repetitivo y el desarrollador puede centrarse únicamente en las funcionalidades necesarias.

Características del registro Java

Las siguientes son las características del disco que lo convierten en una característica interesante:

  • Los objetos de registro tienen un constructor implícito con todos los parámetros como variables de campo .
  • Los objetos de registro tienen métodos implícitos de obtención de campos para cada variable de campo.
  • Los objetos de registro tienen métodos de establecimiento de campos implícitos para cada variable de campo.
  • Los objetos de registro tienen una implementación sensata implícita de los métodos hashCode() , equals() y toString() .
  • Con Java 15, los métodos nativos no se pueden declarar en los registros.
  • Con Java 15, los campos de registro implícitos no son definitivos y la modificación mediante reflexión generará IllegalAccessException.

Ejemplo sin utilizar el registro Java

Creemos un programa simple sin usar registro donde crearemos un objeto Estudiante e imprimiremos sus detalles. El Estudiante tiene tres propiedades, id, nombre y nombre de clase. Para crear un estudiante, hemos creado un constructor parametrizado, métodos setter, getter, iguales y métodos hashcode. Así, nuestra clase de Estudiante se completa con casi 60+ líneas.

package com.achirou;

public class Tester {
   public static void main(String args[]) {
      // create student objects
      Student student1 = new Student(1, "Mahesh", "XII");
      Student student2 = new Student(2, "Sudhir", "XII");

      // print the students
      System.out.println(student1);
      System.out.println(student2);

      // check if students are same
      boolean result = student1.equals(student2);
      System.out.println(result);

      // check if students are same
      result = student1.equals(student1);
      System.out.println(result);

      // get the hashcode
      System.out.println(student1.hashCode());
      System.out.println(student2.hashCode());
   }
}

class Student{
   private int id;
   private String name;
   private String className;

   Student(int id, String name, String className){
      this.id = id;
      this.name = name;
      this.className = className;
   }

   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getClassName() {
      return className;
   }
   public void setClassName(String className) {
      this.className = className;
   }

   @Override
   public String toString() {
      return "Student[id: " + id + ", name: " + name 
         + ", class: " + className + "]";
   }

   @Override
   public boolean equals(Object obj) {
      if(obj == null || !(obj instanceof Student) ) {
         return false;
      }
      Student s = (Student)obj;

      return this.name.equals(s.name) 
         && this.id == s.id 
         && this.className.equals(s.className);
   }

   @Override
   public int hashCode() {
      int prime = 19;
      int result = 1;
      result = prime * result + ((name == null) ? 0 : name.hashCode());
      result = prime * result + ((className == null) ? 0 : className.hashCode());
      result = prime * result + id;
      return result;
   }  
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Student[id: 1, name: Mahesh, class: XII]
Student[id: 2, name: Sudhir, class: XII]
false
true
371251946
288252156

Ejemplo de uso del registro Java

Recreemos el programa anterior usando el registro donde estamos creando un objeto Estudiante como registro e imprimiendo sus detalles. El Estudiante tiene tres propiedades, id, nombre y nombre de clase. Aquí puede ver la diferencia: la clase de Estudiante completa se reemplaza con una línea de código como registro de Estudiante.

package com.achirou;

public class Tester {
   public static void main(String args[]) {
      // create student objects
      Student student1 = new Student(1, "Mahesh", "XII");
      Student student2 = new Student(2, "Sudhir", "XII");

      // print the students
      System.out.println(student1);
      System.out.println(student2);

      // check if students are same
      boolean result = student1.equals(student2);
      System.out.println(result);

      // check if students are same
      result = student1.equals(student1);
      System.out.println(result);

      // get the hashcode
      System.out.println(student1.hashCode());
      System.out.println(student2.hashCode());
   }
}

record Student(int id, String name, String className) {}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Student[id: 1, name: Mahesh, class: XII]
Student[id: 2, name: Sudhir, class: XII]
false
true
371251946
288252156

También podemos agregar métodos personalizados en los registros. Pero generalmente no es necesario.

Registro Java para interfaces selladas

Como los registros son definitivos por defecto y pueden ampliar las interfaces . Podemos definir interfaces selladas y dejar que los registros las implementen para una mejor gestión del código.

Ejemplo: uso de registros Java para interfaces selladas

Considere el siguiente ejemplo:

package com.achirou;

public class Tester {
   public static void main(String[] args) {
      Person employee = new Employee(23, "Robert");
      System.out.println(employee.id());
	  System.out.println(employee.name());
   }
}
sealed interface Person permits Employee, Manager {
   int id();
   String name();
}
record Employee(int id, String name) implements Person {}
record Manager(int id, String name) implements Person {}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

23
Robert

Anulación de métodos de registros Java

Podemos anular la implementación de un método de registro fácilmente y proporcionar nuestra propia implementación.

Ejemplo: anular métodos de registro de Java

Considere el siguiente ejemplo:

package com.achirou;

public class Tester {
   public static void main(String args[]) {
      // create student objects
      Student student = new Student(1, "Mahesh", "XII");

      System.out.println(student);
   }
}

record Student(int id, String name, String className) {
   public String toString() {
      return "Id: " + id + ", Name: " + name + ", class: " + className ;
   }
}

Compilemos y ejecutemos el programa anterior, esto producirá el siguiente resultado:

Id: 1, Name: Mahesh, class: XII

Java: herramientas de empaquetado

En Java 14, se introdujo una nueva herramienta de empaquetado , jpackage , para reemplazar javapackager . javapackager era parte del kit JavaFX y se introdujo en Java 8. A partir de Java 11, JavaFX no es una característica estándar de la API de Java, javapackager no forma parte de la oferta estándar. jpackage sirve para este propósito. jpackage permite a los desarrolladores empaquetar el archivo jar en un formato instalable nativo como exe/msi para Windows, pkg/dmg para MacOS, etc.

El desarrollador puede usar jlink para comprimir los módulos JDK requeridos al mínimo de módulos y usar jpackage para crear una imagen liviana.

Necesidad de jpackager

Cuando se va a distribuir software, la forma preferida es entregar un paquete instalable al usuario final. Este paquete instalable generalmente contiene el JDK, los módulos, los archivos dependientes y las configuraciones, y proporciona al usuario una forma familiar de instalar el software. No se debe exigir a los usuarios que instalen JRE o JDK como requisito previo para ejecutar la aplicación Java. jpackage maneja todos estos casos y empaqueta todos los archivos necesarios junto con JRE/JDK en un instalador nativo.

Opciones de línea de comando para jpackager

jpackage es una herramienta de línea de comandos y proporciona varias opciones para personalizar el software instalable. A continuación se detallan algunas de las características que proporciona jpackager:

  • El desarrollador puede proporcionar un ícono personalizado.
  • El desarrollador puede proporcionar una ubicación específica para instalar la aplicación.
  • El desarrollador puede pasar los argumentos de la aplicación a la aplicación y utilizar las opciones de JVM al iniciar la aplicación.
  • El desarrollador puede configurar asociaciones de archivos para iniciar la aplicación.
  • El desarrollador puede configurar la opción para modificar las opciones del grupo de menús específicos de la plataforma para iniciar la aplicación.
  • El desarrollador puede configurar varios lanzadores para iniciar la aplicación.
  • Usando XCode, también se puede firmar un paquete. Sin embargo, esto sólo se aplica a MacOS.

Requisito previo

Los siguientes son los requisitos previos para utilizar la herramienta jpackager para preparar un instalable.

  • El primer requisito es tener el JDK y la aplicación de software.
  • Obtenga la herramienta de empaquetado específica de la plataforma como se especifica a continuación:
    • Windows : para crear EXE/MSI instalable, se requiere una biblioteca de terceros wix 3.0 o posterior
    • Ubuntu Linux : para crear un paquete RPM, DEB, necesitamos el paquete fakeroot.
    • Red Hat Linux : para crear un paquete RPM, DEB, necesitamos el paquete rpm-build.
    • MacOS : podemos crear un paquete utilizando las herramientas de línea de comandos de Xcode. La opción -mac-sign se puede utilizar para firmar el paquete y -icon se puede utilizar para proporcionar un icono personalizado.
  • El paquete de solicitud debe prepararse según la plataforma. Para cada plataforma, debemos ejecutar el comando por separado.

Crear un paquete

Podemos crear el paquete usando el siguiente comando:

Sintaxis

jpackage –input lib \
  –name Tester\
  –main-jar Tester.jar \
  –main-classcom.laprovittera.Tester\
  –type msi \
  –java-options ‘–enable-preview’

Dónde

  • entrada : carpeta que contiene las bibliotecas requeridas.
  • nombre – nombre del paquete instalable
  • main-jar : archivo jar que se ejecutará para iniciar la aplicación.
  • clase principal : nombre de la clase principal en el JAR que se lanzará. Si el archivo MANIFEST.MF en el JAR principal contiene el nombre de la clase principal, entonces esta opción no es necesaria.
  • tipo – tipo de instalable. DMG/PKG para MacOS, opciones MSI/EXE en Windows y opciones DEB/RPM en Linux.
  • java-options – opciones para el tiempo de ejecución de Java

Este comando creará un archivo MSI que se puede instalar en Windows y la aplicación se puede utilizar como cualquier otro software.

Ejemplo de un paquete

public class APITester {

   public static void main(String[] args) {

      System.out.println(«Welcome to achirou.com.»);

   }  

}

Compilar y ejecutar el programa

$javac APITester.java
$jar cf APITester.jar APITester.class

Producción

Para el ejecutable de Windows, debe descargar WiX Toolset v3.11.2 (wix311-binaries.zip) y agregar el kit de herramientas a su ruta.

Una vez que se crea el jar y se establece la ruta, coloque el jar en una carpeta llamada lib y ejecute el siguiente comando para crear un instalador MSI de Windows.

$jpackage –input lib –name APITester –main-jar APITester.jar –main-class APITester –type msi

Java 16 – Recolectores de basura

Java 15 ha convertido ZGC, Z Garbage Collector en una característica estándar. Era una característica experimental hasta Java 15. Es un recolector de basura altamente escalable y de baja latencia. ZGC se introdujo en Java 11 como una característica experimental ya que la comunidad de desarrolladores consideró que era demasiado grande para lanzarla temprano.

ZGC tiene un alto rendimiento y funciona de manera eficiente incluso en el caso de aplicaciones de datos masivos, por ejemplo, aplicaciones de aprendizaje automático. Garantiza que no haya pausas prolongadas durante el procesamiento de datos debido a la recolección de basura. Es compatible con Linux, Windows y MacOS.

Con Java 16, el procesamiento ZGC Thread-Stack se traslada de Safepoints a Concurrent Phase y mejora en gran medida su eficiencia. A continuación se detallan las mejoras realizadas.

  • El procesamiento de la pila de subprocesos se trasladó desde los puntos seguros de ZGC.
  • El procesamiento de la pila se vuelve perezoso, cooperativo, concurrente e incremental.
  • Todos los demás procesamientos raíz por subproceso se eliminan de los puntos seguros de ZGC.
  • Los subsistemas HotSpot pueden procesar pilas de forma perezosa.

Java 16: otras mejoras

JEP 338 − Vector API (Incubator)

JIT Compiler optimiza los algoritmos aritméticos transformando algunas operaciones escalares (un elemento a la vez) en operaciones vectoriales (varios elementos a la vez) automáticamente. Pero los desarrolladores no tenían control sobre este proceso. Incluso no todas las operaciones escalares se pueden convertir en operaciones vectoriales. Con este JEP, se introduce una nueva API VECTOR para permitir a los desarrolladores realizar operaciones vectoriales explícitamente.

Es un módulo de incubadora, jdk.incubator.vector, para expresar cálculos vectoriales para compilar de manera confiable en tiempo de ejecución con instrucciones óptimas de hardware vectorial.

JEP 347 − Habilitar funciones del lenguaje C++14

Hasta JDK 15, JDK admite los estándares del lenguaje C++98/03. Con JEP 347, ahora Java permite formalmente cambios en el código fuente de C++ dentro del JDK para usar funciones del lenguaje C++14 y para proporcionar orientación específica sobre cuáles de esas funciones se pueden usar en el código HotSpot.

JEP 357/369 − Migrar de Mercurial a GitHub

Con JEP 357/369, el código fuente OpenJDK se traslada de Mercurial a Git/GitHub. Los siguientes son los factores principales de este movimiento.

  • Tamaño de archivo grande de metadatos del sistema de control de versiones (Mercurial)
  • Herramientas disponibles
  • Alojamiento disponible

JEP 380 − Canales de socket de dominio Unix

Los sockets de dominio Unix sirven para la comunicación entre procesos (IPC) en el mismo host, para intercambiar datos entre procesos. Estos sockets son similares a los sockets TCP/IP, excepto que se dirigen mediante nombres de ruta del sistema de archivos en lugar de direcciones de Protocolo de Internet (IP) y números de puerto. La mayoría de las plataformas Unix, Windows 10 y Windows Server 2019, admiten sockets de dominio Unix. JEP 380 agregó soporte de socket de dominio Unix a SocketChannel y ServerSocketChannel.

Java 16: obsolescencia y eliminaciones

Deprecación

  • Los métodos ThreadGroup como stop, destroy, isDestroyed, setDaemon e isDaemon están en desuso y se eliminarán en versiones futuras. Estas API/mecanismos para destruir un grupo de subprocesos son defectuosos y los métodos que admiten la destrucción explícita o automática de un grupo de subprocesos están en desuso.
  • Las API de encadenamiento de señales como sigset y signal están obsoletas y su uso está obsoleto. sigaction es multiplataforma y es compatible con API para procesos multiproceso.
  • Las API java.security.cert que representan DN como objetos Principal o String están en desuso.
  • Se eliminan las curvas elípticas que están obsoletas o no implementadas utilizando fórmulas y técnicas modernas del proveedor SunEC.

Mudanzas

  • Se elimina la clase no pública java.awt.PeerFixer. Su propósito era proporcionar soporte de deserialización de objetos ScrollPane creados antes de JDK 1.1.1.
  • jaotc, se elimina una herramienta experimental de compilación Java Ahead-of-Time. También se elimina el compilador JIT experimental basado en Java, Graal.
  • Los certificados raíz con claves públicas RSA de 1024 bits débiles se han eliminado del almacén de claves cacerts.

En cuanto salga la versión 24 agregaremos sus novedades

No te detengas, sigue avanzando

Aquí tienes un propósito para este 2024 que debes considerar seriamente: si has querido mejorar tus habilidades en hacking, Ciberseguridad y programación ahora es definitivamente el momento de dar el siguiente paso. ¡Desarrolla tus habilidades aprovechando nuestros cursos a un precio increíble y avanza en tu carrera!

Universidad Hacking. Todo en Ciberseguridad. Curso Completo

Aprende Hacking Ético y Ciberseguridad sin necesitar conocimientos Previos. Practica Hacking Ético y Ciberseguridad aquí

Calificación: 4,6 de 5 (2.877 calificaciones) 15.284 estudiantes Creado por Alvaro Chirou • 1.800.000+ Enrollments Worldwide

Lo que aprenderás

  • Aprende Seguridad informática
  • Te enseñare Hacking Ético
  • Veremos Ciberseguridad
  • La base principal del Hacking, Redes
  • Esto es alternativo que puedes aprender, Programación (python)
  • Necesitaras saber Python para, Hacking con Python
  • Te enseñare Análisis de Malware, además haremos laboratorios, practicas y ejecutaremos Malware para que veas su comportamiento
  • Te enseñare a reforzar tu Privacidad y Anonimato
  • Aprenderás una de las herramientas mas populares por excelencia en el mundo del Hacking, Metasploit
  • Es importante que aprendas Seguridad informática Mobile ya que usamos nuestro celular como una PC
  • Veremos también el top 10 de Owasp Web
  • Veremos también el top 10 de Owasp mobile
  • Veremos también el top 10 de Owasp API
  • Ante la demanda del mercado, te enseñare Seguridad informática para empresas
  • Veras también la suit de herramientas de seguridad informática en un sistema operativo, Kali Linux
  • Herramientas de hacking para el celular en Termux
  • Seguridad informática en WordPress
  • Análisis de trafico en Wireshark

El Hacking Ético y Ciberseguridad es Transversal a todo lo que sea Tecnología. Es decir, cualquier dispositivo inteligente, sea Celular, Computadora, o hasta hoy un Vehículo, debe haber Seguridad informática.

¿Esto que significa?

Que hoy más que nunca, se necesitan personas capacitadas en este rubro para trabajar.

Por esa razón cree esta formación profesional para compartirte mis conocimientos y experiencia en la materia y puedas iniciar en este mundo del Hacking Ético y Ciberseguridad.

Te voy a estar acompañando en el proceso de aprendizaje, donde si estas empezando desde 0, sin conocimientos previos, no es un impedimento ya que iniciaremos como si no supieras nada de la materia.

Y si sos una persona con conocimientos, podrás iniciar directamente en el nivel más avanzado o en el que tu elijas.

Como en todos mis cursos en udemy, tendrás muchísima practica para que materialices lo que vas aprendiendo.

Empieza a aprender ya mismo!

Aprende con nuestros más de 100 cursos que tenemos disponibles para vos

¿Te gustaría enterarte de cuando lanzamos descuentos y nuevos cursos?

Sobre los autores

Álvaro Chirou

Yo soy Álvaro Chirou, tengo más de 20 Años de experiencia trabajando en Tecnología, eh dado disertaciones en eventos internacionales como OWASP, tengo más de 1.800.000 estudiantes en Udemy y 100 formaciones profesionales impartidas en la misma. Puedes serguirme en mis redes:

Laprovittera Carlos

Soy Laprovittera Carlos. Con más de 20 años de experiencia en IT brindo Educación y Consultoría en Seguridad de la Información para profesionales, bancos y empresas. Puedes saber más de mi y de mis servicios en mi sitio web: laprovittera.com y seguirme en mis redes:

¿Quieres iniciarte en hacking y ciberseguridad pero no sabes por dónde empezar? Inicia leyendo nuestra guia gratuita: https://achirou.com/como-iniciarse-en-ciberseguridad-y-hacking-en-2024/ que te lleva de 0 a 100. Desde los fundamentos más básicos, pasando por cursos, recursos y certificaciones hasta cómo obtener tu primer empleo.

SIGUE APRENDIENDO GRATIS CON NUESTRAS GUIAS

Cómo Iniciarse en Hacking y Ciberseguridad en 2024

Curso Gratis de Programación

Curso Gratis Linux – Capitulo 1 – Introducción a Linux

Curso Gratis de Redes – Capitulo 1 – Tipos de redes y servicios

Como iniciarse en TRY HACK ME – Complete Beginner #1

OSINT #1 Más de 200 Search Tools