JavaRush /Java Blog /Random-IT /Pausa caffè #37. Un nuovo futuro per Java. Prospettive JV...

Pausa caffè #37. Un nuovo futuro per Java. Prospettive JVM, Kotlin e Java dopo il 2020

Pubblicato nel gruppo Random-IT
Fonte: Medium Java viene criticato principalmente per due cose: la verbosità e la quantità di codice boilerplate che viene generato in molti casi senza evidente necessità. Anche se Java mi è sempre piaciuto, non posso dire che queste affermazioni siano sbagliate. È proprio vero: un dettaglio eccessivo in Java a volte può essere molto fastidioso. Dobbiamo però ammettere che non viviamo in un mondo ideale e nella maggior parte dei casi dobbiamo scegliere il minore tra due mali. Pausa caffè #37.  Un nuovo futuro per Java.  Prospettive JVM, Kotlin e Java dopo il 2020 - 1Fin dalla sua nascita Java non è stato perfetto: lo sappiamo tutti, ma la vera domanda è perché prima non è stato fatto nulla per risolvere questi problemi. Penso che l'unica ragione per cui i cambiamenti hanno richiesto così tanto tempo è perché il linguaggio Java mancava di concorrenza e le cose erano proprio come erano prima. Java ha dominato il mercato, probabilmente grazie alla mancanza di concorrenti seri e ai grandi sforzi compiuti prima da Sun e poi da Oracle. L'elevato livello di sicurezza dei tipi offerto da Java e la buona strutturazione del linguaggio lo hanno reso molto popolare per progetti di grandi dimensioni. Inoltre, è un linguaggio multipiattaforma che gira sulla propria macchina virtuale. Tutto ciò, combinato con l'ottimizzazione automatica delle prestazioni tramite il compilatore JIT, riduce al minimo l'impatto di un codice scritto in modo inadeguato. Tutto sommato, è una serie di ragioni piuttosto convincenti per utilizzare Java. Ma cosa è successo dopo? Quello che è successo è che sono arrivati ​​sul mercato nuovi linguaggi che possono essere eseguiti nella stessa JVM di Java. Linguaggi che hanno eliminato alcuni dei maggiori inconvenienti di Java e, in alcuni casi, hanno offerto agli sviluppatori un ambiente più piacevole con una barriera all’ingresso più bassa. Prima di continuare, facciamo il punto e diamo una breve occhiata alla storia dei linguaggi JVM.

Storia dei linguaggi JVM

Innanzitutto vorrei chiarire una cosa: non ho menzionato alcuni dei linguaggi JVM esistenti perché non hanno mai avuto abbastanza supporto per essere considerati candidati ad un uso diffuso nel nostro settore. Cominciamo ora la nostra breve panoramica sulla storia dei linguaggi JVM. Per prima cosa avremo Java, il linguaggio più antico e popolare nel mondo JVM. Java è stato rilasciato ufficialmente nel gennaio 1996, quindi il linguaggio esiste da 24 anni. Non male, vero? Java era originariamente un linguaggio puramente imperativo che seguiva uno stile di programmazione orientato agli oggetti; era anche un linguaggio fortemente tipizzato. La sintassi di Java è in qualche modo simile ai linguaggi C++ e C, ma è considerata una versione migliorata perché scrivere codice in Java è molto più semplice che in C o C++. D'altra parte, abbiamo l'argomento più importante tra i suoi detrattori: la verbosità. Il secondo linguaggio JVM era Groovy. Esiste dal 2003, anche se la sua prima versione standardizzata, la 1.0, è apparsa solo nel gennaio 2007. Il vantaggio di Groovy è che può essere utilizzato come linguaggio di scripting. Groovy è un linguaggio tipizzato dinamicamente, quindi il controllo del tipo viene eseguito in fase di runtime. Questo è uno dei motivi per cui ad alcuni sviluppatori non piace Groovy. Scrivi il tuo codice in Groovy e sembra corretto in fase di compilazione, ma poi in fase di esecuzione ti rendi conto che qualcosa non va. Poi è comparso un altro linguaggio popolare: parliamo di Scala. È stato rilasciato nel 2004. Ha portato un nuovo modello di lavoro nel mondo JVM: programmazione funzionale e approccio dichiarativo. Fondamentalmente Scala è stato il primo linguaggio a introdurre il concetto di immutabilità, che è stato poi utilizzato per potenziare Java. D'altra parte, ai detrattori non piace Scala a causa della sua grammatica complessa e della leggibilità piuttosto bassa. Il linguaggio successivo ad emergere dal mondo JVM fu Clojure, un linguaggio puramente funzionale. È diventato piuttosto popolare di recente, anche se è apparso nel 2007. Clojure è un linguaggio basato su LISP che si caratterizza per la sua semplicità e l'uso di funzioni semplici. Tra i suoi svantaggi c'è che è tipizzato dinamicamente (come Groovy) e la curva di apprendimento è molto più ripida poiché la sua sintassi è completamente diversa da altri linguaggi JVM. E infine, abbiamo Kotlin. Kotlin è apparso per la prima volta nel febbraio 2016 e da allora la sua popolarità non ha smesso di crescere. È sviluppato da JetBrains con l'obiettivo principale: risolvere i problemi Java più famosi. In base alla progettazione, Kotlin ha mantenuto tutti i vantaggi di Java, ma allo stesso tempo ha risolto molti problemi. Questi sono i linguaggi JVM più importanti. Come ho detto, ci mancano altre lingue che non sono così popolari: Jython, JRuby, Ceylon, Fantom, ecc. Se lo desideri, puoi scoprire l' elenco completo delle lingue JVM esistentisuWikipedia. Probabilmente ti sei reso conto che Java non ha avuto molta concorrenza nei primi otto o dieci anni dopo la sua creazione, ma da allora le cose sono cambiate. Quindi la concorrenza è un bene o un male?

Vantaggi della crescente concorrenza

Java non è cambiato molto nei suoi primi anni. Probabilmente perché non era necessario. Questa lingua è stata ampiamente utilizzata ed è sempre stata molto popolare, nonostante sia lungi dall'essere perfetta. Ma poi sono comparsi i concorrenti, linguaggi più moderni che hanno offerto nuove funzionalità e risolto alcuni dei problemi che affliggevano da tempo gli sviluppatori Java. Consideriamo ad esempio il linguaggio Scala. La popolarità di Scala è in crescita dal 2009. Gli sviluppatori hanno accolto favorevolmente questo nuovo stile funzionale, che ha offerto loro una maggiore flessibilità e la capacità di scrivere codice parallelo in modo semplice e sicuro. Come ha risposto Oracle a questa nuova tendenza? Nel 2014 sono comparsi Java Lambda e Stream. Penso che siamo tutti d'accordo sul fatto che questo è il momento in cui Java ha compiuto il passo più grande verso la sconfitta di Scala. Ora ogni programmatore sa che Scala non è più di moda. Pausa caffè #37.  Un nuovo futuro per Java.  Prospettive JVM, Kotlin e Java dopo il 2020 - 2Un altro vantaggio di avere più concorrenti nel mondo JVM sono i costanti miglioramenti apportati al compilatore JIT e alla JVM. Ora molte più persone sono interessate a ottimizzare la JVM e a migliorare le prestazioni. Quindi la competizione fa bene a tutti! L'alternativa più recente a Java è il linguaggio Kotlin. Il suo aspetto è stato molto importante per lo sviluppo di Java, poiché il nuovo linguaggio, in un certo senso, ha mostrato a Oracle la via da seguire. L'esempio di Kotlin ha dimostrato che è possibile preservare i vantaggi di Java, ma creare un linguaggio più compatto in cui sia più veloce scrivere il codice. Se guardi il grafico di Google Trends, puoi vedere che dal 2016 al 2018 la popolarità di Kotlin è cresciuta rapidamente. Ma negli ultimi due anni l’entusiasmo è diminuito. Pausa caffè #37.  Un nuovo futuro per Java.  Prospettive JVM, Kotlin e Java dopo il 2020 - 3Oracle ha esaminato da vicino la risposta del settore a Kotlin. Se guardi le note sulla versione di JDK 15 , vedrai che alcune delle nuove funzionalità Java sono copie di ciò che è arrivato in Kotlin. Si tratta di nuove voci Java , nuovi blocchi di testo (stringhe multilinea con virgolette triple) e un nuovo operatore switch, che è essenzialmente una copia dell'operatore whenin Kotlin. Tutto ciò di cui abbiamo parlato è ciò che io chiamo “Kotlinizzazione di Java”. Diventando un concorrente più forte, Kotlin ha mostrato a Java la strada da seguire.

"Kotlinizzazione" di Java

Alcune delle prossime funzionalità Java rappresenteranno miglioramenti significativi in ​​termini di leggibilità e risolveranno uno dei maggiori punti deboli del linguaggio Java: la sua verbosità. Si potrebbe sostenere che molte delle funzionalità Java annunciate siano sospettosamente simili ad alcune funzionalità di Kotlin. Ma tieni presente che la maggior parte di essi sono versioni pre-release . Ciò significa che se installi JDK 14 o JDK 15 (quando verrà rilasciato), non sarai in grado di utilizzarli per impostazione predefinita. Le anteprime delle funzionalità Java sono nuove funzionalità introdotte in una versione ma disabilitate per impostazione predefinita. Sono inclusi nella nuova versione solo per raccogliere feedback dalla comunità degli sviluppatori, quindi potrebbero essere ancora soggetti a modifiche. Questo è il motivo per cui non è consigliabile utilizzarli nel codice di produzione. Per abilitarli in fase di compilazione dovrai effettuare le seguenti operazioni:
javac --enable-preview --release 14
Se desideri abilitarli in fase di runtime, dovrai eseguire quanto segue:
java --enable-preview YourClass
Naturalmente puoi abilitarli anche nel tuo IDE, ma fai attenzione a non abilitare l'anteprima per impostazione predefinita in tutti i tuoi nuovi progetti! Diamo un'occhiata ai cambiamenti che avranno un impatto maggiore sulla nostra codifica nelle future versioni di Java.

Messaggi Java

Java Records è una funzionalità che molti di noi chiedono a gran voce da molto tempo. Immagino che tu ti sia trovato in una situazione in cui dovevi implementare toString , hashCode , equals , nonché getter per ogni campo esistente. Kotlin dispone di classi di dati per risolvere questo problema e Java intende fare lo stesso rilasciando classi di record che Scala già possiede sotto forma di classi case . Lo scopo principale di queste classi è archiviare dati immutabili in un oggetto. Facciamo un esempio per vedere quanto può migliorare Java. Questo è quanto codice dovremmo scrivere per creare e confrontare la nostra 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 anche l'oggetto Addressche 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 + '\'' +
                '}';
    }
}
Probabilmente c'è troppo codice per qualcosa di così semplice, giusto? Vediamo ora come apparirà con le nuove voci Java:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
E non dimentichiamo la classe Address:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
Questa è la stessa cosa che abbiamo scritto prima con così tanto codice. D'accordo: è fantastico. E la quantità di codice che salveremo e la facilità di scrittura! Vediamo ora quali sono le differenze con il nuovo operatore switch.

Operatore miglioratoswitch

Il nuovo operatore switchin Java risolverà alcuni dei vecchi problemi, inclusi alcuni bug e la duplicazione del codice. Con il nuovo operatore switchquesto problema sarà risolto. Per spiegarlo con un esempio, creeremo un'enumerazione DayOfTheWeekin Java:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
Dopodiché il nostro switchci dirà quale posizione della settimana corrisponde a quel giorno. Vediamo prima come possiamo farlo attualmente utilizzando 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 l'istruzione corrente, switchdovremo utilizzare una variabile e, se tralasciamo uno dei giorni della settimana, il nostro codice verrà compilato correttamente. Questo è uno dei problemi con gli operatori switch: sono troppo soggetti a errori. In che modo Java 14 migliora le cose? Diamo un'occhiata:
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");
Come puoi vedere, i nuovi operatori switchpossono essere utilizzati come espressioni, non solo come istruzioni. Il risultato è più conciso ed espressivo. Questo basterebbe a convincere molti di noi a usarli, ma uno dei miglioramenti più importanti è che ora le dichiarazioni switchnon verranno compilate a meno che non copriamo tutti i casi nel nostro file switch. Ci mostrerà questo errore, ad esempio:
Error:(9, 24) java: the switch expression does not cover all possible input values
D'ora in poi sarà impossibile saltare i casi presso i nostri operatori switch. Questo è molto simile agli operatori whendi Kotlin, di cui puoi leggere nella documentazione . Diamo anche uno sguardo ai nuovi blocchi di testo.

Blocchi di testo

Ti sei mai lamentato di quanto sia difficile assegnare un BLOB JSON a una variabile in Java? Java dispone di sequenze multilinea che è possibile descrivere racchiudendole tra virgolette triple. Una volta rilasciata ufficialmente questa funzionalità, diventerà molto più semplice descrivere lunghe sequenze su più righe. Vediamo le differenze tra le due modalità. Se vogliamo utilizzare JSON formattato in una variabile, risulta negativo:
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" +
                "}} ";
Quando invece verranno rilasciati i nuovi blocchi di testo tutto diventerà molto più semplice:
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;"
                    }
                }}
                """;
Questo sembra decisamente migliore. Tutto questo è già supportato in Kotlin, come puoi vedere nelle sue definizioni di tipo . Abbiamo quindi visto che Java "eredita" molte soluzioni ai propri problemi da uno dei suoi concorrenti: Kotlin. Non sappiamo se Oracle abbia risposto in tempo per contrastare l'ascesa di Kotlin o se sia arrivato troppo tardi. Personalmente ritengo che Java stia facendo i giusti passi avanti, anche se questi cambiamenti sono stati in qualche modo avviati dai suoi concorrenti e potrebbero arrivare con qualche ritardo.

Conclusione

Penso che la competizione sia la cosa migliore che sia mai accaduta al linguaggio Java. La mia impressione è che altrimenti Java riposerebbe sugli allori. Inoltre, i concorrenti di Java hanno dimostrato che è possibile un modo diverso di programmare, mostrando come andare avanti ed evitare modi di scrivere codice obsoleti e inefficienti. I cambiamenti futuri renderanno Java più potente che mai, un linguaggio adattato all’era moderna, un linguaggio che vuole evolversi.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION