Java 14 otvaranje - nove karakteristike Record, instanceof i switch
U Javi 14 uvedeni su Record i „pattern matching” instanceof, a switch izraz iz Java 12 je postao stalni. Hajde da ih zajedno prodjemo.
01. Preuzimanje JDK 14
Do 30. marta 2023. vec je objavljen Java 20, ali nije LTS (dugorocna podrška) verzija; Java 17, 11 i 8 su trenutno LTS verzije koje imaju podršku.
Da bismo otvorili kutiju, prvo moramo preuzeti JDK 14 (ili noviju, ako je imas). Odakle drugde? Moze se preuzeti sa dva izvora — sa Oracle-a za komercijalnu verziju ili sa jdk.java.net za open-source verziju. Mi cemo izabrati ovo drugo.
Trenutno koristim Windows, pa biram Windows zip paket za preuzimanje. Nakon preuzimanja ne zaboravi da ga raspakovati.
02. Nadogradnja IntelliJ IDEA
Do 30. marta 2023. najnovija verzija IntelliJ IDEA je 2023.1.
Potrebno je nadograditi IDEA na Early Access Program verziju 2020.1 EAP (ili noviju, ako vec koristis noviju), u suprotnom nece moci da podrži nove karakteristike Java 14.
Adresa za preuzimanje Community verzije je:
[https://www.jetbrains.com/idea/nextversion/#section=windows](https://www.jetbrains.com/idea/nextversion/#section=windows)Pri instalaciji mozes ukloniti prethodnu verziju ili je zadržati. Nakon toga, kreirajmo novi Java 14 projekat.
03. instanceof
Prema reduosledu novina, krenimo od instanceof. Klasicna upotreba instanceof izgleda ovako:
public class OldInstanceOf {
public static void main(String[] args) {
Object str = "Java 14, stvarno je dobar";
if (str instanceof String) {
String s = (String)str;
System.out.println(s.length());
}
}
}Prvo se pomocu instanceof u if uslovu proverava da li je tip promenljive str String (prvi korak), zatim se u if bloku radi eksplicitni cast u String (drugi korak) i pri tome se deklarise nova promenljiva koja prima rezultat kastovanja (treci korak).
Tri koraka nisu neka nauka, ali oseca se da bi mogla da postoji bolja sintaksa — i evo, Java 14 je razmislio o tome.
public class NewInstanceOf {
public static void main(String[] args) {
Object str = "Java 14, stvarno je dobar";
if (str instanceof String s) {
System.out.println(s.length());
}
}
}Direktno u if uslovu, pri proveri tipa, moze se dodati i promenljiva — pa vise nema potrebe ni za kastovanjem ni za deklaracijom nove promenljive. Nije li to elegantno? Ali „pattern matching” instanceof u Javi 14 je preview verzija i podrazumevano nije ukljucen, pa ce ovaj kod prijaviti cudnu gresku pri kompajliranju (u Javi 14 nije podržan pattern matching instanceof).
Kako resiti taj problem? U podesavanjima projekta rucno podesi verziju jezika.
Nakon tog podesavanja, greska pri kompajliranju nestaje. Izlaz programa je:
10Odlično, stvarno je dobar. Zanima te šta je Java kompajler uradio ispod haube? Pogledaj dekompajlirani bajtkod i bice ti jasno.
public class NewInstanceOf {
public NewInstanceOf() {
}
public static void main(String[] args) {
Object str = "Java 14, stvarno je dobar";
String s;
if (str instanceof String && (s = (String)str) == (String)str) {
System.out.println(s.length());
}
}
}Pre provere if uslova, prvo se declarise promenljiva s, a zatim se unutar if uslova radi kastovanje s = (String)str) i proverava se da li su s i str jednaki. Zaista odlicna karakteristika koja oslobadja developerima produktivnost — jako se nadam da ce postati stalna u sledecoj verziji.
04. Records
U jednom od prethodnih clanaka govorio sam o nepromenljivoscu klase; ona je definisana ovako:
public final class Writer {
private final String name;
private final int age;
public Writer(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}Dakle, za Records — jedan Record predstavlja jedno nepromenljivo stanje. Iako pruza metode poput equals(), hashCode(), toString(), konstruktor i getere za polja, on nije namenjen tome da zameni klase promenljivih objekata (nema setere), niti funkcionalnosti koje nudi Lombok.
Hajde da Records-om zamenimo prethodnu klasu Writer:
public record Writer(String name, int age) { }Eto, jedna linija koda i gotovo. Kljucno je da dobijas bogatiju funkcionalnost nego u prethodnom kodu — pogledaj dekompajlirani bajtkod:
public final class Writer extends java.lang.Record {
private final java.lang.String name;
private final int age;
public Writer(java.lang.String name, int age) { /* compiled code */ }
public java.lang.String toString() { /* compiled code */ }
public final int hashCode() { /* compiled code */ }
public final boolean equals(java.lang.Object o) { /* compiled code */ }
public java.lang.String name() { /* compiled code */ }
public int age() { /* compiled code */ }
}Klasa je final, polja su private final, konstruktor ima dva parametra, postoje metode toString(), hashCode(), equals(), a geteri su tu — samo bez prefiksa „get”. Ali nema setera, što znaci da Records zaista cilja na nepromenljive objekte — utvrdjeno. Kako onda koristiti Records?
public class WriterDemo {
public static void main(String[] args) {
Writer writer = new Writer("Chenmo Wang Er",18);
System.out.println("toString: " + writer);
System.out.println("hashCode: " + writer.hashCode());
System.out.println("name: " + writer.name());
System.out.println("age: " + writer.age());
Writer writer1 = new Writer("Chenmo Wang Er", 18);
System.out.println("equals: " + (writer.equals(writer1)));
}
}Izlaz programa je:
toString: Writer[name=Chenmo Wang Er, age=18]
hashCode: 1130697218
name: Chenmo Wang Er
age: 18
equals: trueOdlično, stvarno dobro — ubuduce je definisanje nepromenljivih klasa mnogo jednostavnije. Jako se nadam da ce ovo postati stalna karakteristika u sledecoj verziji.
05. switch izraz
O switch izrazu vec detaljno pisah u jednom od prethodnih clanaka; klikni na link da pregledaš. Prošle su dve nedelje i switch izraz je konacno „sazreo” i postao stalni — cestitke.
Secam se da je taj clanak, kad je objavljen na sajtu Juejin, dobio mnoštvo besmislenih komentara tipa: „Mislio sam da imas neku tehniku, a koristis Java 13, dok mi jos uvek stojimo na Javi 8!” To je ocigledno zatvoreno misljenje i jako je stetno; programeri ne bi smeli tako da misle. Najjednostavnija cinjenica je da je i Java 6 nekad bila klasik, a nije li je zamenila Java 8? S vremenom ce i Java 8 biti zamenjena jos revolucionarnijom verzijom — uvek treba napredovati.
Što se tice switch izraza, evo jednog prostog primera:
public class SwitchDemo {
enum PlayerTypes {
TENNIS,
FOOTBALL,
BASKETBALL,
PINGPANG,
UNKNOWN
}
public static void main(String[] args) {
System.out.println(createPlayer(PlayerTypes.BASKETBALL));
}
private static String createPlayer(PlayerTypes playerType) {
return switch (playerType) {
case TENNIS -> "teniser Federer";
case FOOTBALL -> "fudbaler Ronaldo";
case BASKETBALL -> "kosarkas LeBron James";
case PINGPANG -> "stoni teniser Ma Long";
case UNKNOWN -> throw new IllegalArgumentException("nepoznato");
};
}
}Pored nove sintakse sa ->, moze se koristiti i kao rezultat return-a — stvarno dobro.
06. Text Blocks
Pre nego što su se pojavili tekstualni blokovi (Text Blocks), za nadovezivanje viselinijskih stringova bilo nam je potrebno mnogo engleskih navodnika i znakova plus, što je izgledalo kao „povez za ocajne”. Ako se bas poklopi da treba nadovezivati HTML tekst (ili sirov SQL), potrebno je voditi racuna o uvlacima razmacima, a za prelazak u novi red koristiti escape sekvencu \n — za developera je to obična katastrofa.
public class OldTextBlock {
public static void main(String[] args) {
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
System.out.println(html);
}
}U Javi 14 je potpuno drugacije:
public class NewTextBlock {
public static void main(String[] args) {
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
System.out.println(html);
}
}Visak engleskih navodnika, znakova plus i escape sekvenci za novi red — sve je nestalo. Postignuto je iskljucivo pomocy tri engleska navodnika na pocetku i na kraju. Mogu samo reci — dobro je, stvarno je dobro!
