TSM - Noutăți Java de la versiunea 8 la 16

Ovidiu Mățan - Fondator @ Today Software Magazine


Vom discuta în acest articol despre feature-urile adăugate limbajului Java în ultimele versiuni. Fiecare programator ar trebui să le cunoască și să le folosească dacă versiunea Java folosită în proiect o permite. Menționăm principalele noi capabilități introduse: lambdas, stream, method reference, declararea variabilelor fără a specifica un tip prin folosirea var sau switchul care returnează valori. În rândurile următoare vom trece prin fiecare dintre ele cu ajutorul exemplelor de cod.

Imagine de ansamblu

În momentul de față, pe site-ul Oracle, sunt disponibile trei versiuni diferite de Java pentru descărcare, ultimele release-uri GA (General Availability) fiind pentru fiecare apărute în 20 aprilie 2021:

Release-urile noilor versiuni au loc o dată la șase luni, Java 17 fiind planificat să apară în luna septembrie.

Java versions timeline - Sursa - https://www.marcobehler.com/guides/a-guide-to-java-versions-and-features

Java 8

Feature-uri introduse:

Realizăm o simplă aplicație prin care inițializăm un șir cu valorile 1 - 10 după care le afișăm.

Versiunea clasică:

List data=new ArrayList();
for (int i=0;i<10;i++){
    data.add(i);
}
for (int i=0;i<10;i++){
    System.out.println(i);
}

Folosim acum java.util.stream și lambdas

List list=
  new ArrayList<>();

IntStream intStream=
  IntStream.range(0,10);

intStream.forEach(
  value->list.add(value));

Simplificăm funcția lambda prin folosirea operatorului de method reference ::

IntStream intStream=
  IntStream.range(0,10);

intStream.forEach(list::add);

Afișarea listei se poate realiza, de asemenea, prin utilizarea operatorului :: și metoda statică println:

list.forEach(System.out::println);

Java 9

S-a adăugat suportul de a avea metode private în interfețe. La o primă vedere, poate să pară un feature inutilizabil, dat fiind că nu ar putea fi apelat de către clasele ce implementează interfața sau de obiectele instanță ale acestora. Soluția vine din Java 8 când au fost introduse metodele default în interfețe. Prin intermediul acestora se poate defini o implementare de bază a unei metode.

În exemplul de mai jos am definit o interfață Square și am implementat-o în clasa RealSquare

public interface Square {
    public int perfectArea();
    public int width();
    public default double realSquareArea(){
        return perfectArea()*correction();
    }

    private double correction(){
        return 0.99;
    }
}

public class RealSquare implements Square{
    private int myWidth;

    public RealSquare(int width){
        this.myWidth=width;
    }
    @Override
    public int perfectArea() {
        return this.myWidth*this.myWidth;
    }

    @Override
    public int width() {
        return this.myWidth;
    }
}

În clasa de bază, valorificăm interfața și putem apela metoda default care utilizează intern metoda privată a interfeței :

Square sq=new RealSquare(10);
System.out.println(sq.perfectArea());
System.out.println(sq.realSquareArea());

Bineînțeles că metoda default realSquareArea()poate fi suprascrisă, dar în felul acesta nu vom mai putea să apelăm metoda privată din interfață. Din această abordare se naște întrebarea legată de utilitatea reală a acestora.

Java 10

Versiunea Java 10 a introdus conceptul de var pentru declararea unei variabile. Putem în felul acesta declara instanța intStream astfel:

var intStream=IntStream.range(0,10);

Este o modalitate de declarare mai simplă și practică ce folosește mecanismul de introspecție. În acest fel, apropie Java mai mult de limbajele funcționale, cum ar fi JavaScript.

Java 11

Putem rula o aplicație Java fără o a mai compila. În principiu, se referă la o aplicație simplă care conține toate dependențele:

java Main.java

Java 13

Metodele switch pot returna acum valori:

int val=switch(str){
    case "red"->1;
    case "blue"->2;
    default -> 0;
};
System.out.println(val);

Java 14

A fost adăugat suportul pentru Records. O modalitate simplă de autogenerare a metodelor get/set și a constructorului.

public record SquareRec(int size, String color){
        public String extraInfo(){
            return color+":"+size;
        }
    }

Am definit o clasă cu două variabile membru, size și color. De asemenea, am adăugat și o metodă specifică acesteia: extraInfo(). Folosirea sa este normală și ne-a ușurat munca, nu mai avem de declarat getSize(), getColor(), constructorul și, bineînțeles, asignarea valorilor. Remarcăm lipsa de generare a metodelor set().

SquareRec sqr=new SquareRec(10,"red");
System.out.println(sqr.color());
System.out.println(sqr.extraInfo());

Java 15

A fost adăugat suportul pentru interfețe sau clase abstracte sealed. În felul acesta, putem controla exact cine are dreptul să implementeze o interfață sau o clasă abstractă. Putem astfel defini interfața Square în felul următor:

public sealed interface Square permits RealSquare, SecondSquare {
…
}

Trebuie menționat faptul acele clase care implementează metoda Square trebuie declarate finale (final)

Java 16

Nu a introdus modificări de limbaj noi, în schimb, au fost definitivate o serie de capabilități care erau la stadiul de preview.

Concluzie

În rândurile de mai sus au fost enumerate principalele schimbări care au apărut în ultimii ani în limbajul Java. Personal, mă bucur de faptul că asistăm la o evoluție continuă a acestuia, în cadrul căreia noile capabilități vin să adauge o mai mare flexibilitate și o optimizare a modului în care scriem cod.