JavaRush /Blogue Java /Random-PT /Pausa para café #37. Um novo futuro para Java. Perspectiv...

Pausa para café #37. Um novo futuro para Java. Perspectivas de JVM, Kotlin e Java após 2020

Publicado no grupo Random-PT
Fonte: Medium Java é criticado principalmente por duas coisas: verbosidade e a quantidade de código clichê que é gerado em muitos casos sem necessidade óbvia. Embora eu sempre tenha gostado de Java, não posso dizer que essas afirmações estejam erradas. É verdade: detalhes excessivos em Java às vezes podem ser muito irritantes. Contudo, devemos admitir que não vivemos num mundo ideal e, na maioria dos casos, temos de escolher o menor de dois males. Pausa para café #37.  Um novo futuro para Java.  Perspectivas de JVM, Kotlin e Java após 2020 - 1Desde o seu início, Java não tem sido perfeito: todos nós sabemos disso, mas a verdadeira questão é por que nada foi feito antes para resolver esses problemas. Acho que a única razão pela qual as mudanças demoraram tanto é porque a linguagem Java não tinha concorrência e as coisas estavam exatamente como estavam. Java dominou o mercado, provavelmente devido à falta de concorrentes sérios e aos grandes esforços feitos primeiro pela Sun e depois pela Oracle. O alto nível de segurança de tipo que o Java oferece e a boa estruturação da linguagem a tornaram muito popular para grandes projetos. Além disso, é uma linguagem multiplataforma que roda em uma máquina virtual própria. Combinado com a otimização automática de desempenho através do compilador JIT, tudo isso minimiza o impacto de código mal escrito. Resumindo, é um conjunto bastante convincente de razões para usar Java. Mas o que aconteceu a seguir? O que aconteceu é que surgiram no mercado novas linguagens que podem rodar na mesma JVM que Java. Linguagens que eliminaram alguns dos maiores inconvenientes do Java e, em alguns casos, ofereceram aos desenvolvedores um ambiente mais agradável e com menor barreira de entrada. Antes de continuarmos, vamos fazer um balanço e dar uma breve olhada na história das linguagens JVM.

História das linguagens JVM

Primeiramente, gostaria de deixar uma coisa clara: não mencionei algumas das linguagens JVM existentes porque elas nunca tiveram suporte suficiente para serem consideradas candidatas para uso generalizado em nossa indústria. Vamos agora começar nossa breve visão geral da história das linguagens JVM. Primeiro teremos Java, a linguagem mais antiga e popular do mundo JVM. Java foi lançado oficialmente em janeiro de 1996, portanto a linguagem já existe há 24 anos. Nada mal, certo? Java era originalmente uma linguagem puramente imperativa que seguia um estilo de programação orientado a objetos; também era uma linguagem fortemente tipada. A sintaxe do Java é um pouco semelhante à das linguagens C++ e C, mas é considerada uma versão melhorada porque escrever código em Java é muito mais fácil do que em C ou C++. Por outro lado, temos o maior argumento entre seus detratores – a verbosidade. A segunda linguagem JVM foi Groovy. Existe desde 2003, embora sua primeira versão padronizada, 1.0, só tenha aparecido em janeiro de 2007. A vantagem do Groovy é que ele pode ser usado como linguagem de script. Groovy é uma linguagem de tipagem dinâmica, portanto a verificação de tipo é feita em tempo de execução. Esta é uma das razões pelas quais alguns desenvolvedores não gostam do Groovy. Você escreve seu código no Groovy e ele parece correto em tempo de compilação, mas em tempo de execução você percebe que algo está errado. Surgiu então outra linguagem popular: falamos de Scala. Foi lançado em 2004. Ele trouxe um novo modelo de trabalho para o mundo JVM: programação funcional e abordagem declarativa. Basicamente, Scala foi a primeira linguagem a introduzir o conceito de imutabilidade, que foi então usado para aprimorar o Java. Por outro lado, os detratores não gostam de Scala por causa de sua gramática complexa e baixa legibilidade. A próxima linguagem a emergir do mundo JVM foi Clojure, uma linguagem puramente funcional. Tornou-se bastante popular recentemente, embora tenha surgido em 2007. Clojure é uma linguagem baseada em LISP que se caracteriza pela sua simplicidade e uso de funções simples. Entre suas desvantagens está o fato de ser digitado dinamicamente (como o Groovy) e a curva de aprendizado ser muito mais acentuada, pois sua sintaxe é completamente diferente de outras linguagens JVM. E finalmente, temos Kotlin. Kotlin apareceu pela primeira vez em fevereiro de 2016 e, desde então, sua popularidade não parou de crescer. É desenvolvido pela JetBrains com o objetivo principal: corrigir os mais famosos problemas de Java. Por design, Kotlin manteve todas as vantagens do Java, mas ao mesmo tempo resolveu muitos problemas. Estas são as linguagens JVM mais importantes. Como eu disse, sentimos falta de algumas outras linguagens que não são tão populares: Jython, JRuby, Ceylon, Fantom, etc. Se desejar, você pode descobrir a lista completa de linguagens JVM existentesna Wikipédia. Você provavelmente já percebeu que Java não teve muita concorrência nos primeiros oito ou dez anos após sua criação, mas as coisas mudaram desde então. Então, a competição é boa ou ruim?

Benefícios do aumento da concorrência

Java não mudou muito em seus primeiros anos. Provavelmente porque não era necessário. Esta linguagem tem sido amplamente utilizada e sempre foi muito popular, apesar de estar longe de ser perfeita. Mas então surgiram concorrentes, linguagens mais modernas que ofereciam novos recursos e resolviam alguns dos problemas que atormentavam os desenvolvedores Java há muito tempo. Por exemplo, vejamos a linguagem Scala. A popularidade do Scala tem crescido desde 2009. Os desenvolvedores acolheram favoravelmente esse novo estilo funcional, que lhes proporcionou maior flexibilidade, bem como a capacidade de escrever código paralelo com segurança e facilidade. Como a Oracle respondeu a essa nova tendência? Em 2014, surgiram Java Lambdas e Streams. Acho que todos podemos concordar que foi aí que o Java deu o maior passo para derrotar Scala. Agora qualquer programador sabe que Scala não está mais na moda. Pausa para café #37.  Um novo futuro para Java.  Perspectivas de JVM, Kotlin e Java após 2020 - 2Outro benefício de ter mais concorrentes no mundo JVM são as constantes melhorias feitas no compilador JIT e na JVM. Agora, muito mais pessoas estão interessadas em otimizar a JVM e melhorar o desempenho. Portanto, a competição é boa para todos! A alternativa mais recente ao Java é a linguagem Kotlin. Seu surgimento foi muito importante para o desenvolvimento do Java, pois a nova linguagem, de certa forma, mostrou ao Oracle o caminho a seguir. O exemplo do Kotlin mostrou que é possível preservar as vantagens do Java, mas criar uma linguagem mais compacta e mais rápida para escrever código. Se você olhar o gráfico do Google Trends, verá que de 2016 a 2018, a popularidade do Kotlin cresceu rapidamente. Mas nos últimos dois anos o entusiasmo diminuiu. Pausa para café #37.  Um novo futuro para Java.  Perspectivas de JVM, Kotlin e Java após 2020 - 3A Oracle analisou de perto a resposta da indústria ao Kotlin. Se você olhar as notas de lançamento do JDK 15 , verá que alguns dos novos recursos do Java são cópias do que veio no Kotlin. Estas são novas entradas Java , novos blocos de texto (strings multilinhas com aspas triplas) e um novo operador switch, que é essencialmente uma cópia do operador whenem Kotlin. Tudo o que falamos é o que chamo de “Kotlinização de Java”. Ao se tornar um concorrente mais forte, Kotlin mostrou ao Java o caminho a seguir.

"Kotlinização" de Java

Alguns dos próximos recursos Java serão melhorias significativas em termos de legibilidade e resolverão um dos maiores pontos fracos da linguagem Java – sua verbosidade. Pode-se argumentar que muitos dos recursos Java anunciados são suspeitamente semelhantes a alguns recursos do Kotlin. Mas observe que a maioria deles são versões de pré-lançamento . Isso significa que se você instalar o JDK 14 ou JDK 15 (quando for lançado), não poderá usá-los por padrão. As visualizações de recursos Java são novos recursos introduzidos em uma versão, mas são desativados por padrão. Eles estão incluídos na nova versão apenas para obter feedback da comunidade de desenvolvedores, portanto ainda podem estar sujeitos a alterações. É por isso que não é recomendado usá-los em código de produção. Para habilitá-los em tempo de compilação, você precisará fazer o seguinte:
javac --enable-preview --release 14
Se quiser habilitá-los em tempo de execução, você precisará executar o seguinte:
java --enable-preview YourClass
Claro, você também pode habilitá-los em seu IDE, mas tome cuidado para não habilitar a visualização por padrão em todos os seus novos projetos! Vamos dar uma olhada nas mudanças que terão um impacto maior em nossa codificação em versões futuras do Java.

Postagens Java

Java Records é um recurso que muitos de nós clamamos há muito tempo. Suponho que você se encontrou em uma situação em que precisava implementar toString , hashCode , equals , bem como getters para cada campo existente. Kotlin possui classes de dados para resolver esse problema , e Java pretende fazer o mesmo liberando classes de registro que Scala já possui na forma de classes de caso . O principal objetivo dessas classes é armazenar dados imutáveis ​​em um objeto. Vamos dar um exemplo para ver o quão melhor o Java pode se tornar. Esta é a quantidade de código que teríamos que escrever para criar e comparar nossa classe 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 +
                '}';
    }
}
E também o objeto Addressque ele contém:
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 + '\'' +
                '}';
    }
}
Provavelmente há muito código para algo tão simples, certo? Vamos agora ver como isso ficará com as novas entradas Java:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
E não vamos esquecer a classe Address:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
É a mesma coisa que escrevemos anteriormente com tanto código. Concordo: isso é incrível. E a quantidade de código que vamos economizar e a facilidade de escrever! Vamos agora ver quais são as diferenças com o novo operador switch.

Operador aprimoradoswitch

O novo operador switchem Java resolverá alguns dos problemas antigos, incluindo alguns bugs e duplicação de código. Com o novo operador switcheste problema será resolvido. Para explicar isso com um exemplo, vamos criar um enum DayOfTheWeekem Java:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
Depois disso, o nosso switchnos dirá qual posição da semana corresponde a esse dia. Vamos primeiro ver como podemos fazer isso atualmente 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");
Com a instrução atual, switchprecisaremos usar uma variável e, se perdermos um dos dias da semana, nosso código será compilado perfeitamente. Este é um dos problemas dos operadores switch: eles são muito propensos a erros. Então, como o Java 14 melhora as coisas? Vamos dar uma olhada:
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 você pode ver, os novos operadores switchpodem ser usados ​​como uma expressão, não apenas como uma instrução. O resultado é mais conciso e expressivo. Isso seria suficiente para convencer muitos de nós a usá-los, mas uma das principais melhorias é que agora as declarações switchnão serão compiladas a menos que cubramos todos os casos em nosso arquivo switch. Ele nos mostrará este erro, por exemplo:
Error:(9, 24) java: the switch expression does not cover all possible input values
A partir de agora será impossível pular caso em nossas operadoras switch. Isso é muito semelhante aos operadores whenem Kotlin, sobre os quais você pode ler na documentação . Vamos também dar uma olhada nos novos blocos de texto.

Blocos de texto

Você já reclamou da dificuldade de atribuir um blob JSON a uma variável em Java? Java possui sequências multilinhas que você pode descrever colocando-as entre aspas triplas. Assim que esse recurso for lançado oficialmente, será muito mais fácil descrever sequências longas em várias linhas. Vejamos as diferenças entre os dois modos. Se quisermos usar JSON formatado em uma variável, fica ruim:
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 outro lado, quando os novos blocos de texto forem lançados, tudo ficará muito mais simples:
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;"
                    }
                }}
                """;
Isso definitivamente parece melhor. Tudo isso já é suportado no Kotlin, como você pode ver em suas definições de tipo . Portanto, vimos que o Java “herda” muitas soluções para seus próprios problemas de um de seus concorrentes: Kotlin. Não sabemos se a Oracle respondeu a tempo de combater a ascensão do Kotlin ou se chegou tarde demais. Pessoalmente, acredito que Java está dando os passos certos, mesmo que essas mudanças tenham sido de alguma forma iniciadas por seus concorrentes e possam vir com algum atraso.

Conclusão

Acho que a competição é a melhor coisa que já aconteceu com a linguagem Java. Minha impressão é que, caso contrário, o Java descansaria sobre os louros. Além disso, os concorrentes do Java mostraram que uma forma diferente de programar é possível, mostrando como avançar e evitar formas desatualizadas e ineficientes de escrever código. As mudanças futuras tornarão o Java mais poderoso do que nunca, uma linguagem adaptada à era moderna, uma linguagem que quer evoluir.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION