¿Qué esperar de Java en 2020?

2020 ya está en su apogeo, discutamos qué cambios en el mundo de Java nos esperan este año. Este artículo enumerará las principales tendencias de Java y JDK. Y estaré contento con las adiciones de los lectores en los comentarios.

Inmediatamente haga una reserva de que el artículo es más un personaje de investigación. Los detalles sobre cada tema discutido se pueden encontrar en el sitio web del proyecto correspondiente o en publicaciones en fuentes abiertas.

imagen

Vamos a empezar. Desafortunadamente, inmediatamente tendrá que decepcionar a aquellos que no siguen demasiado el ciclo de lanzamiento de Java, pero que esperan un programa de soporte largo (LTS). Este año estamos esperando lanzamientos con solo un corto ciclo de vida de soporte (STS).
El primero consideraremos el próximo lanzamiento de JDK 14, que debería lanzarse a mediados de marzo. En este ciclo de lanzamiento, se reclaman hasta 16 JEP. Aquí está la lista completa:
305:Coincidencia de patrones por ejemplo de (Vista previa)
343:Herramienta de embalaje (incubadora)
345:Asignación de memoria compatible con NUMA para G1
349:Transmisión de eventos JFR
352:Búferes de bytes mapeados no volátiles
358:NullPointerExceptions útiles
359:Registros (vista previa)
361:Cambiar expresiones (estándar)
362:Desaprobar los puertos Solaris y SPARC
363:Retire el recolector de basura de barrido de marcas concurrentes (CMS)
364:ZGC en macOS
365:ZGC en Windows
366:Desaprobar la combinación ParallelScavenge + SerialOld GC
367:Eliminar las herramientas y API de Pack200
368:Bloques de texto (segunda vista previa)
370:API de acceso a memoria externa (incubadora)

Muchos JEP de esta lista fueron ampliamente cubiertos en la conferencia Joker 2019. Me centraré en los que me parecen más interesantes.

Coincidencia de patrones por ejemplo de (Vista previa)


El largo JEP finalmente saldrá en Vista previa. Creo que si eres un programador en ejercicio que ha estado escribiendo código Java durante muchos años, entonces has encontrado este dolor más de una vez:

if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.toUpperCase());
}

Si escribió o está escribiendo código también en Kotlin, entonces el dolor de ver el código Java es un poco peor. Los participantes del proyecto Amber nos presentarán su visión de la coincidencia de patrones en Java, lo que debería reducir este dolor. Con la llegada de Java 14, podemos reescribir el ejemplo de la siguiente manera:

if (obj instanceof String s) {
   System.out.println(s.toUpperCase());
}

Parece que el complemento no es tan valioso: guardamos una línea de código. Pero supongamos que queremos hacer lo siguiente:

if (obj instanceof String) {
    String s = (String) obj;
    if (s.contains(“prefix_”)) {
       return s.toUpperCase();
    }
}
return null;

Se ve voluminoso, ¿no? Probemos lo mismo, pero con Pattern Matching.

return (obj instanceof String s) && s.contains(“prefix_”) ? s.toUpperCase() : null;

Entonces obviamente será mejor. Pero recuerde que el estado de esta funcionalidad es Vista previa. Veamos qué cambia con el tiempo. Para mí, definitivamente mejorará mi vida.

NullPointerExceptions útiles


2020 está en el patio, ¿y todavía escribes para que NullPointerExceptions vuele por ti? No te preocupes, probablemente no seas el único. Goetz Lindenmaier y Ralf Schmelter no sugirieron una nueva forma de alejarse de NullPointerExceptions (Opcional todavía está con nosotros), pero propusieron mejorar el proceso de depuración de la aplicación para comprender exactamente dónde se encuentra nulo. Entonces, imaginemos que escribimos el código a las cinco en punto ... por la noche, por supuesto. Y escribimos esta función:

public String getStreetFromRequest(Request request) {
   return request.getAddress().getStreet().toUpperCase();
}

No está mal, pero se olvidaron por completo de poner anotaciones @Nullable y @Nonnull y verificar la dirección en los campos transmitidos. Obtuve una NullPointerException. ¿Qué nos dice la excepción?

Exception in thread "main" java.lang.NullPointerException
	at Program.getStreetFromRequest(Program.java:10)
	at Program.main(Program.java:6)

Por desgracia, solo vemos una fila, una clase y una pila. ¿A dónde exactamente regresó nulo? Tal vez esto es una solicitud? Tal vez getAddress () devuelto nulo? O tal vez getStreet ()? Bueno, las cadenas de llamadas a veces duelen.

Los autores de JEP proponen una solución: al lanzar una excepción, se supone que debe pasar por alto la pila para determinar dónde regresó exactamente nulo y luego mostrar el nombre de las variables / métodos. Probemos con Java 14 con la opción -XX: + ShowCodeDetailsInExceptionMessages. Comenzamos y nos ponemos un poco diferentes:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "Address.getStreet()" is null
	at Program.getStreetFromRequest(Program.java:10)
	at Program.main(Program.java:6)

Ahora sabemos que la programación nocturna no es buena (pero a veces conduce a la finalización de las tareas a tiempo), y en nuestro programa olvidamos que la dirección no es un campo obligatorio.

Registros (vista previa)


¿Sigue generando getters / setters / equals / hashCode con idea? ¡Entonces este JEP viene a ti!
Las clases de datos están lejos del último lugar en la vida de un desarrollador de software de aplicación. Cada vez tenemos que generar métodos de clases de datos usando nuestro IDE favorito, o usar varios complementos en tiempo de compilación para generar los métodos necesarios, como lombok.

Como resultado, tenemos mucho código similar a este:

public class Request {
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
       this.address = address;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Request request = (Request) o;
        return Objects.equals(address, request.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(address);
    }

    @Override
    public String toString() {
        return "Request{" +
                "address=" + address +
                '}';
    }
}

O tal:
@Data
@AllArgsConstructor
public class Request {
    private Address address;
}

En Java 14, los miembros del proyecto Amber proponen una nueva sintaxis para crear clases de datos. Para hacer esto, use el nuevo registro de palabras clave. La sintaxis para Record es ligeramente diferente a la de las descripciones de clase o enumeración, y es ligeramente similar a Kotlin. El código anterior se puede reescribir de la siguiente manera:

public record Request(Address address) {
}

Todos los campos de registro tienen modificadores privados y finales por defecto. El registro en sí es una clase final y no se puede heredar de otra clase, pero puede implementar interfaces. En las clases de registro del cuadro obtenemos: métodos getters, un constructor público, cuyos parámetros son todos campos de registro en el orden de descripción, equals / hashCode y toString. De lo desagradable: no podemos agregar campos al registro, excepto los especificados después del nombre de la clase. Por ejemplo, este código generará un error:

public record Request(Address address) {
   private final String anotherParameter; // compilation error
}

Bloques de texto (segunda vista previa)


Los bloques de texto se lanzaron como vistas previas en Java 13. Los usuarios giramos, giramos y retroalimentamos (creo sinceramente que ya está utilizando Java 13 con vista previa). Como resultado, los creadores de Java hicieron cambios menores en los bloques de texto. Primero, ahora podemos indicar explícitamente dónde termina la línea, colocando la secuencia de escape \ s en nuestra línea. Aquí hay un ejemplo:

public static void main(String[] args) {
        final var test = """
                This is the long text block with escape string \s
                that is really well done            \s
                """;
        System.out.println(test);
}

Ahora establecemos explícitamente todos los espacios en el carácter \ s y todos los caracteres de espacio se guardarán en el carácter \ s.

En segundo lugar, ahora podemos ajustar largas líneas de un bloque de texto sin recibir \ n caracteres en la línea final. Para hacer esto, solo necesitamos agregar \ en el salto de línea. Cómo se ve:

public static void main(String[] args) {
        final var test = """
                This is the long text block with escape string \
                that is really well-done functional            
                """;
System.out.println(test);

Después de la ejecución, obtenemos la siguiente línea: "Este es el bloque de texto largo con cadena de escape que está realmente bien hecho funcional".

Una buena adición, me parece. Realmente espero traducir esta funcionalidad a estándar.
Es probable que todas las características que revisamos sean discutidas ampliamente en las próximas conferencias. Algunos de ellos ya se discutieron en Joker 2019. Asegúrese de consultar la charla Joker 2019 sobre "Evolución de características en Java 13 y más allá" de Cay Horstmann.

Y algunas cosas más interesantes.


Hay dos elementos interesantes en la lista JEP en la incubadora. Para empezar, tendremos una herramienta universal que creará instaladores para diferentes sistemas operativos (bueno, finalmente, quiero decirles a los que bailaron alrededor de la instalación de programas en Windows). Jpacker podrá crear instaladores msi / exe para Windows, paquetes macOS y rpm / deb para Linux. Veamos qué sucede con esto, pero en esos raros casos en que hice algo para escritorio, personalmente sufrí el hecho de que no tenía una herramienta regular para ensamblar el instalador.

Aún más prometedor es la nueva API para acceder a "Memoria extranjera", es decir Cualquier tipo de memoria nativa o persistente. Esta API es principalmente útil para creadores de bases de datos Java o creadores de framework como Netty, por ejemplo. Ellos, utilizando Unsafe y ByteBuffer, optimizan el acceso a la memoria con el montón fuera de lo posible.

Próximo lanzamiento. Alegría y frustración


En septiembre, estamos esperando otra versión de soporte a corto plazo en el número 15. La lista de JEP que se incluirá en la versión final aún está abierta. Hasta ahora, puede ver muchos cambios diferentes en el lenguaje en sí, en la biblioteca estándar y la máquina virtual.
Aquí está la lista de candidatos (puede cambiar rápidamente, mira aquí: bugs.openjdk.java.net/secure/Dashboard.jspa?selectPageId=19114 ):
111:Additional Unicode Constructs for Regular Expressions
116:Extended Validation SSL Certificates
134:Intuitive Semantics for Nested Reference Objects
152:Crypto Operations with Network HSMs
198:Light-Weight JSON API
218:Generics over Primitive Types
300:Augment Use-Site Variance with Declaration-Site Defaults
301:Enhanced Enums
302:Lambda Leftovers
303:Intrinsics for the LDC and INVOKEDYNAMIC Instructions
306:Restore Always-Strict Floating-Point Semantics
338:Vector API (Incubator)
339:Compiler Intrinsics for Java SE APIs
348:Compiler Intrinsics for Java SE APIs
356:Enhanced Pseudo-Random Number Generators
360:Sealed Types (Preview)
371:Hidden Classes

Como puede ver, la lista todavía no tiene muchas cosas esperadas. En primer lugar, para mí es Project Loom. La idea del paralelismo estructural ha sido muy popular en los últimos años. Las rutinas pueden simplificar enormemente la tarea de la computación paralela competitiva y la ejecución asincrónica de tareas. Se pueden ver excelentes ejemplos de implementación de esta idea, por ejemplo, en los idiomas Kotlin (corutinas) y Go (goroutinas). Java también está explorando la idea del paralelismo estructural, y ya hay primeros resultados. Por ahora, solo puede verlos al recopilar el JDK del repositorio del proyecto.

Valhalla, un proyecto muy prometedor, todavía no nos ha complacido con ningún avance. En Joker 2019 se presentó un informe interesante sobre este proyecto ("¿Requiere Java tipos" en línea "? Una visión limitada del ingeniero de rendimiento en el proyecto Valhalla" por Sergey Kuksenko).

¿Qué se presenta en la lista?

Lo primero que llama la atención es la API JSON. La pregunta surge de inmediato: ¿por qué? Claramente no hay una respuesta definitiva. La sección JEP sobre motivación dice que JSON se ha convertido en un estándar para los servicios web, y ahora es el momento de adaptar Java SE para interactuar con JSON (a pesar de que ahora hay un montón de bibliotecas para analizar JSON). La explicación más probable es la capacidad de los desarrolladores de software de utilizar una pequeña API central para reducir el tamaño del paquete sin tener que arrastrar al pesado Jackson hacia ellos. No veo ninguna otra explicación, porque ni siquiera tendrá enlace de datos.

También vemos una serie de mejoras relacionadas con la API criptográfica. Para comenzar, los desarrolladores de JDK desean expandir el proceso de validación de certificados SSL agregando soporte para certificados EVSSL. Con esta API en Java, puede determinar si un certificado EV (Validación Extendida) confía en una conexión SSL. El certificado EVSSL de acuerdo con la directriz será totalmente compatible. También se agregará un nuevo algoritmo criptográfico EdDSA y se mejorará la verificación de la criptografía HSM.

De las cosas del lenguaje, destacaría la implementación de genéricos en primitivas. Todos los que alguna vez programaron en C # y cambiaron a Java, probablemente podrían hacer la pregunta, ¿por qué no pueden hacer tipos genéricos en primitivas? La respuesta es simple: los genéricos solo funcionan con objetos, y las primitivas no son objetos y, en particular, no heredan una clase Object. No es el primer año que se ha librado una guerra sobre este tema, y ​​Brian Goetz está volviendo a ella nuevamente. No hay nada especial para describir hasta ahora. La tarea es clara: admitir construcciones como List. Pero incluso en este momento hay 13 preguntas abiertas que deben resolverse antes de implementar esta funcionalidad. Honestamente, me pregunto cómo terminará esta serie.

Y lo último que quiero tocar son los tipos sellados. Este es el siguiente paso hacia la coincidencia de patrones. Tipos Sellados es una extensión de lenguaje que implementa el sellado (modificador) y permite palabras clave para una clase o interfaz.

Usando la clase sellada, limitamos el número de descendientes a solo aquellas clases que se especifican en los permisos (una restricción explícita) o en la misma unidad de compilación (archivo). Descripción de ejemplo de una clase sellada:

// 
public abstract sealed class Base {
   public static class ChildA extends Base{}
   public static class ChildB extends Base{}
}

// 
public sealed interface BaseInterface permits ChildC, ChildD{
}

//  
public class ChildC implements BaseInterface {
}
//  
public class ChildD implements BaseInterface {
}

El modificador sellado asegura que solo un conjunto limitado de descendientes pueda extender la clase base o implementar una interfaz. Esta propiedad se puede usar al procesar objetos de estas clases. Y, por supuesto, este es un gran candidato para usar en una declaración de cambio con coincidencia de patrones.

Conclusión


Analizamos las diversas innovaciones de JDK este año. Algunos de ellos dispararán, otros no. Pero sobre todo en los nuevos JDK, espero nuevas optimizaciones pequeñas (o no tan) que aceleren nuestros programas con cada lanzamiento de forma gratuita. Y si estuvo en el último Joker 2019 y visitó el informe de Tagir Valeev Java 9-14: Pequeñas optimizaciones, entonces lo más probable, como yo, quedó impresionado por el trabajo que hacen los colaboradores para optimizar JDK. Sus resultados no son visibles a primera vista y no se reflejan en más de un JEP, pero los usamos todos los días.

Buenos lanzamientos de Java para todos nosotros. Explore las nuevas características de la plataforma, vaya a conferencias y siga las tendencias.

All Articles