JavaRush /Blog Java /Random-ES /Pausa para el café #37. Un nuevo futuro para Java. Perspe...

Pausa para el café #37. Un nuevo futuro para Java. Perspectivas de JVM, Kotlin y Java después de 2020

Publicado en el grupo Random-ES
Fuente: Medio Java es criticado principalmente por dos cosas: la verbosidad y la cantidad de código repetitivo que se genera en muchos casos sin una necesidad obvia. Aunque siempre me ha gustado Java, no puedo decir que estas afirmaciones sean incorrectas. Es realmente cierto: el exceso de detalles en Java a veces puede resultar muy molesto. Sin embargo, debemos admitir que no vivimos en un mundo ideal y en la mayoría de los casos tenemos que elegir el menor de dos males. Pausa para el café #37.  Un nuevo futuro para Java.  Perspectivas de JVM, Kotlin y Java después de 2020 - 1Desde sus inicios, Java no ha sido perfecto: todos lo sabemos, pero la verdadera pregunta es por qué no se hizo nada antes para resolver estos problemas. Creo que la única razón por la que los cambios tardaron tanto es porque el lenguaje Java carecía de competencia y las cosas eran como eran. Java dominó el mercado, probablemente debido a la falta de competidores serios y a los grandes esfuerzos realizados primero por Sun y luego por Oracle. El alto nivel de seguridad de tipos que proporciona Java y la buena estructuración del lenguaje lo han hecho muy popular para proyectos grandes. Además, es un lenguaje multiplataforma que se ejecuta en su propia máquina virtual. Combinado con la optimización automática del rendimiento a través del compilador JIT, todo esto minimiza el impacto de un código mal escrito. Considerándolo todo, es un conjunto de razones bastante convincentes para usar Java. ¿Pero qué pasó después? Lo que ha pasado es que han salido al mercado nuevos lenguajes que pueden ejecutarse en la misma JVM que Java. Lenguajes que eliminaron algunos de los mayores inconvenientes de Java y, en algunos casos, ofrecieron a los desarrolladores un entorno más agradable con una barrera de entrada más baja. Antes de continuar, hagamos un balance y echemos un vistazo breve a la historia de los lenguajes JVM.

Historia de los lenguajes JVM

Primero, me gustaría dejar una cosa clara: no mencioné algunos de los lenguajes JVM existentes porque nunca tuvieron suficiente soporte para ser considerados candidatos para un uso generalizado en nuestra industria. Comencemos ahora nuestra breve descripción de la historia de los lenguajes JVM. Primero tendremos Java, el lenguaje más antiguo y popular en el mundo JVM. Java se lanzó oficialmente en enero de 1996, por lo que el lenguaje existe desde hace 24 años. No está mal, ¿verdad? Java era originalmente un lenguaje puramente imperativo que seguía un estilo de programación orientado a objetos; también era un lenguaje fuertemente tipado. La sintaxis de Java es algo similar a la de los lenguajes C++ y C, pero se considera una versión mejorada porque escribir código en Java es mucho más fácil que en C o C++. Por otro lado, tenemos el mayor argumento entre sus detractores: la verbosidad. El segundo lenguaje JVM fue Groovy. Existe desde 2003, aunque su primera versión estandarizada, 1.0, no apareció hasta enero de 2007. La ventaja de Groovy es que se puede utilizar como lenguaje de programación. Groovy es un lenguaje de escritura dinámica, por lo que la verificación de tipos se realiza en tiempo de ejecución. Ésta es una de las razones por las que a algunos desarrolladores no les gusta Groovy. Escribes tu código en Groovy y parece correcto en tiempo de compilación, pero luego, en tiempo de ejecución, te das cuenta de que algo anda mal. Luego apareció otro lenguaje popular: hablamos de Scala. Fue lanzado en 2004. Aportó un nuevo modelo de trabajo al mundo JVM: programación funcional y un enfoque declarativo. Básicamente, Scala fue el primer lenguaje en introducir el concepto de inmutabilidad, que luego se utilizó para mejorar Java. Por otro lado, a los detractores no les gusta Scala debido a su gramática compleja y su legibilidad bastante baja. El siguiente lenguaje que surgió del mundo JVM fue Clojure, un lenguaje puramente funcional. Se ha vuelto bastante popular recientemente, aunque apareció en 2007. Clojure es un lenguaje basado en LISP que se caracteriza por su sencillez y uso de funciones sencillas. Entre sus desventajas están que se escribe dinámicamente (como Groovy) y la curva de aprendizaje es mucho más pronunciada ya que su sintaxis es completamente diferente a la de otros lenguajes JVM. Y finalmente tenemos a Kotlin. Kotlin apareció por primera vez en febrero de 2016 y desde entonces su popularidad no ha dejado de crecer. Está desarrollado por JetBrains con el objetivo principal: solucionar los problemas de Java más famosos. Por diseño, Kotlin conservó todas las ventajas de Java, pero al mismo tiempo resolvió muchos problemas. Estos son los lenguajes JVM más importantes. Como dije, nos perdimos algunos otros lenguajes que no son tan populares: Jython, JRuby, Ceylon, Fantom, etc. Si lo deseas, puedes conocer la lista completa de lenguajes JVM existentes.en Wikipedia. Probablemente te habrás dado cuenta de que Java no tuvo mucha competencia en los primeros ocho o diez años después de su creación, pero las cosas han cambiado desde entonces. Entonces, ¿la competencia es buena o mala?

Beneficios de aumentar la competencia

Java no ha cambiado mucho en sus primeros años. Probablemente porque no era necesario. Este lenguaje ha sido ampliamente utilizado y siempre ha sido muy popular, a pesar de que está lejos de ser perfecto. Pero luego aparecieron competidores, lenguajes más modernos que ofrecían nuevas características y resolvían algunos de los problemas que habían atormentado a los desarrolladores de Java durante mucho tiempo. Por ejemplo, veamos el lenguaje Scala. La popularidad de Scala ha ido creciendo desde 2009. Los desarrolladores acogieron con agrado este nuevo estilo funcional, que les brindó mayor flexibilidad y la capacidad de escribir código paralelo de forma segura y sencilla. ¿Cómo ha respondido Oracle a esta nueva tendencia? En 2014, aparecieron Java Lambdas y Streams. Creo que todos podemos estar de acuerdo en que fue entonces cuando Java dio su mayor paso para derrotar a Scala. Ahora cualquier programador sabe que Scala ya no está de moda. Pausa para el café #37.  Un nuevo futuro para Java.  Perspectivas de JVM, Kotlin y Java después de 2020 - 2Otro beneficio de tener más competidores en el mundo JVM son las constantes mejoras que se realizan en el compilador JIT y JVM. Ahora mucha más gente está interesada en optimizar la JVM y mejorar el rendimiento. ¡Así que la competencia es buena para todos! La alternativa más reciente a Java es el lenguaje Kotlin. Su aparición fue muy importante para el desarrollo de Java, ya que el nuevo lenguaje, en cierto sentido, mostró a Oracle el camino a seguir. El ejemplo de Kotlin demostró que es posible conservar las ventajas de Java, pero crear un lenguaje más compacto en el que sea más rápido escribir código. Si observa el gráfico de Google Trends, puede ver que de 2016 a 2018, la popularidad de Kotlin creció rápidamente. Pero en los últimos dos años el entusiasmo ha disminuido. Pausa para el café #37.  Un nuevo futuro para Java.  Perspectivas de JVM, Kotlin y Java después de 2020 - 3Oracle ha analizado de cerca la respuesta de la industria a Kotlin. Si observa las notas de la versión de JDK 15 , verá que algunas de las nuevas características de Java son copias de lo que vino en Kotlin. Se trata de nuevas entradas de Java , nuevos bloques de texto (cadenas multilínea con comillas triples) y un nuevo operador switch, que es esencialmente una copia del operador whenen Kotlin. Todo de lo que hablamos es lo que yo llamo "Kotlinización de Java". Al convertirse en un competidor más fuerte, Kotlin le mostró a Java el camino a seguir.

"Kotlinización" de Java

Algunas de las próximas características de Java supondrán mejoras significativas en términos de legibilidad y abordarán una de las mayores debilidades del lenguaje Java: su verbosidad. Se podría argumentar que muchas de las características de Java anunciadas son sospechosamente similares a algunas características de Kotlin. Pero tenga en cuenta que la mayoría de ellas son versiones preliminares . Esto significa que si instala JDK 14 o JDK 15 (cuando se lance), no podrá usarlos de forma predeterminada. Las vistas previas de funciones de Java son funciones nuevas que se introducen en una versión pero que están deshabilitadas de forma predeterminada. Se incluyen en la nueva versión únicamente para recopilar comentarios de la comunidad de desarrolladores, por lo que aún pueden estar sujetos a cambios. Por eso no se recomienda utilizarlos en código de producción. Para habilitarlos en el momento de la compilación, deberá hacer lo siguiente:
javac --enable-preview --release 14
Si desea habilitarlos en tiempo de ejecución, deberá ejecutar lo siguiente:
java --enable-preview YourClass
Por supuesto, también puedes habilitarlos en tu IDE, ¡pero ten cuidado de no habilitar la vista previa de forma predeterminada en todos tus proyectos nuevos! Echemos un vistazo a los cambios que tendrán un mayor impacto en nuestra codificación en futuras versiones de Java.

Publicaciones de Java

Java Records es una característica que muchos de nosotros hemos estado pidiendo a gritos durante mucho tiempo. Supongo que te has encontrado en una situación en la que necesitabas implementar toString , hashCode , equals y getters para cada campo existente. Kotlin tiene clases de datos para resolver este problema , y ​​Java pretende hacer lo mismo liberando clases de registro que Scala ya tiene en forma de clases de casos . El objetivo principal de estas clases es almacenar datos inmutables en un objeto. Tomemos un ejemplo para ver cuánto mejor puede llegar a ser Java. Esta es la cantidad de código que tendríamos que escribir para crear y comparar nuestra clase Employee:
package com.theboreddev.java14;

import java.util.Objects;

public class Employee {
    private final String firstName;
    private final String surname;
    private final int age;
    private final Address address;
    private final double salary;

    public Employee(String firstName, String surname, int age, Address address, double salary) {
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSurname() {
        return surname;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(firstName, employee.firstName) &&
                Objects.equals(surname, employee.surname) &&
                Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, surname, age, address, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                ", address=" + address +
                ", salary=" + salary +
                '}';
    }
}
Y también el objeto Addressque contiene:
import java.util.Objects;

public class Address {
    private final String firstLine;
    private final String secondLine;
    private final String postCode;

    public Address(String firstLine, String secondLine, String postCode) {
        this.firstLine = firstLine;
        this.secondLine = secondLine;
        this.postCode = postCode;
    }

    public String getFirstLine() {
        return firstLine;
    }

    public String getSecondLine() {
        return secondLine;
    }

    public String getPostCode() {
        return postCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(firstLine, address.firstLine) &&
                Objects.equals(secondLine, address.secondLine) &&
                Objects.equals(postCode, address.postCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstLine, secondLine, postCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "firstLine='" + firstLine + '\'' +
                ", secondLine='" + secondLine + '\'' +
                ", postCode='" + postCode + '\'' +
                '}';
    }
}
Probablemente haya demasiado código para algo tan simple, ¿verdad? Veamos ahora cómo se verá esto con las nuevas entradas de Java:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
Y no olvidemos la clase Dirección:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
Esto es lo mismo que escribimos antes con tanto código. De acuerdo: esto es asombroso. ¡Y la cantidad de código que vamos a ahorrar y la facilidad de escritura! Veamos ahora cuáles son las diferencias con el nuevo operador switch.

Operador mejoradoswitch

El nuevo operador switchen Java resolverá algunos de los viejos problemas, incluidos algunos errores y la duplicación de código. Con el nuevo operador switcheste problema se solucionará. Para explicar esto con un ejemplo, vamos a crear una enumeración DayOfTheWeeken Java:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
Posteriormente el nuestro switchnos indicará qué posición de la semana corresponde a ese día. Primero veamos cómo podemos hacer esto actualmente usando Java 11.
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = 0;

        switch (dayOfTheWeek) {
            case MONDAY:
                position = 1;
                break;
            case TUESDAY:
                position = 2;
                break;
            case WEDNESDAY:
                position = 3;
                break;
            case THURSDAY:
                position = 4;
                break;
            case FRIDAY:
                position = 5;
                break;
            case SATURDAY:
                position = 6;
                break;
            case SUNDAY:
                position = 7;
                break;
        }

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
Con la declaración actual, switchnecesitaremos usar una variable y, si omitimos uno de los días de la semana, nuestro código se compilará bien. Éste es uno de los problemas de los operadores switch: son demasiado propensos a errores. Entonces, ¿cómo mejora Java 14 las cosas? Echemos un vistazo:
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = switch (dayOfTheWeek) {
            case MONDAY -> 1;
            case TUESDAY -> 2;
            case WEDNESDAY -> 3;
            case THURSDAY -> 4;
            case FRIDAY -> 5;
            case SATURDAY -> 6;
            case SUNDAY -> 7;
        };

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
Como puede ver, los nuevos operadores switchse pueden utilizar como expresión, no sólo como declaración. El resultado es más conciso y expresivo. Esto sería suficiente para convencer a muchos de nosotros de usarlos, pero una de las principales mejoras es que ahora las declaraciones switchno se compilarán a menos que cubramos todos los casos en nuestro archivo switch. Nos mostrará este error, por ejemplo:
Error:(9, 24) java: the switch expression does not cover all possible input values
A partir de ahora será imposible saltarse caso en nuestros operadores switch. Esto es muy similar a los operadores whenen Kotlin, sobre los cuales puede leer en la documentación . Echemos un vistazo también a los nuevos bloques de texto.

Bloques de texto

¿Alguna vez te has quejado de lo difícil que es asignar un blob JSON a una variable en Java? Java tiene secuencias multilínea que puedes describir encerrándolas entre comillas triples. Una vez que esta función se lance oficialmente, será mucho más fácil describir secuencias largas en varias líneas. Veamos las diferencias entre los dos modos. Si queremos usar JSON formateado en una variable, resulta malo:
final String text = "{\"widget\": {\n" +
                "    \"debug\": \"on\",\n" +
                "    \"window\": {\n" +
                "        \"title\": \"Sample Konfabulator Widget\",\n" +
                "        \"name\": \"main_window\",\n" +
                "        \"width\": 500,\n" +
                "        \"height\": 500\n" +
                "    },\n" +
                "    \"image\": { \n" +
                "        \"src\": \"Images/Sun.png\",\n" +
                "        \"name\": \"sun1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 250,\n" +
                "        \"alignment\": \"center\"\n" +
                "    },\n" +
                "    \"text\": {\n" +
                "        \"data\": \"Click Here\",\n" +
                "        \"size\": 36,\n" +
                "        \"style\": \"bold\",\n" +
                "        \"name\": \"text1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 100,\n" +
                "        \"alignment\": \"center\",\n" +
                "        \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
                "    }\n" +
                "}} ";
Por otro lado, cuando se publiquen los nuevos bloques de texto todo será mucho más sencillo:
final String multiLineText = """
                {"widget": {
                    "debug": "on",
                    "window": {
                        "title": "Sample Konfabulator Widget",
                        "name": "main_window",
                        "width": 500,
                        "height": 500
                    },
                    "image": {\s
                        "src": "Images/Sun.png",
                        "name": "sun1",
                        "hOffset": 250,
                        "vOffset": 250,
                        "alignment": "center"
                    },
                    "text": {
                        "data": "Click Here",
                        "size": 36,
                        "style": "bold",
                        "name": "text1",
                        "hOffset": 250,
                        "vOffset": 100,
                        "alignment": "center",
                        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
                    }
                }}
                """;
Esto definitivamente se ve mejor. Todo esto ya está soportado en Kotlin, como puedes ver en sus definiciones de tipos . Hemos visto que Java "hereda" muchas soluciones a sus propios problemas de uno de sus competidores: Kotlin. No sabemos si Oracle respondió a tiempo para combatir el ascenso de Kotlin o si llegó demasiado tarde. Personalmente, creo que Java está dando los pasos correctos, incluso si estos cambios fueron iniciados de alguna manera por sus competidores y pueden llegar con cierto retraso.

Conclusión

Creo que la competencia es lo mejor que le ha pasado al lenguaje Java. Mi impresión es que de lo contrario Java se dormiría en los laureles. Además, los competidores de Java han demostrado que es posible una forma diferente de programar, mostrando cómo avanzar y evitar formas obsoletas e ineficientes de escribir código. Los cambios futuros harán que Java sea más poderoso que nunca, un lenguaje adaptado a la era moderna, un lenguaje que quiere evolucionar.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION