Wkrótce Ty też przeniesiesz się na Javę 17
Najnowsze wydanie LTS Javy ukazało się we wrześniu. Niektórzy powiedzą, że przecież czym tu się zachwycać, a niektórzy stwierdzą, że jest to wielki krok dla ludzkości. Spójrzmy na najważniejsze rzeczy, które wydarzyły się w Javie w ciągu ostatnich 3 lat, pomijając przy tym wszystkie dziwactwa. Poniżej kilka przykładów zmian, jakie zostały wprowadzone na przestrzeni lat.
Wreszcie, wieloliniowe Stringi
Tak, teraz zamiast okropnego Stringa, który sprawia, że wyrywasz sobie tylko włosy z głowy (Ostrzeżenie! Następny przykład! Nie patrzeć, jeśli łatwo zaimponować!), jak ten:
public static final String EXAMPLE_JSON = "{\n" +
" \"menu\": {\n" +
" \"header\": \"SVG Viewer\",\n" +
" \"items\": [\n" +
" {\"id\": \"Open\"},\n" +
" {\"id\": \"OpenNew\", \"label\": \"Open New\"}\n" +
" ]\n" +
"}";
Masz możliwość składania JSON, XML, itp.
public static final String EXAMPLE_JSON = """
{
"menu": {
"header": "SVG Viewer",
"items": [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"}
]
}""";
Jak powiedział Borat: „Is nice!!!”
Więcej informacji na temat NPE
Przed Javą 17, gdy miałem do czynienia z NullPointerException
, dostawałem jedynie suche wyjaśnienie i odniesienie do linii kodu. Rozważmy taki oto przykład:
CarPark.getDefault().getLambo().wroomWroom();
Jeżeli mam NullPointerException
to gdzie do cholery był null
? Czy jest to instancja CarPark
, czy instancja Car
? W czym tkwi problem?
Java 11 wyjaśnia w ten sposób:
Exception in thread "main" java.lang.NullPointerException
at com.dmytrozzz.Main.main(Main.java:6)
co oznacza: „Wal się. Debuguj i sam znajdź ten błąd, głupku!”
W Javie 17 zastosowano nieco inne podejście:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.dmytrozzz.CarPark.getLambo()" because the return value of "com.dmytrozzz.CarPark.getDefault()" is null
Wreszcie wiem, gdzie dokładnie zawaliłem sprawę!
Wyrażenia switch
Pamiętasz kiedy podstawą do obliczenia wyniku było wiele warunków? Ktoś wyraził to w ten sposób:
var input = X;
var result;
if(input == 0) {
result = 1;
} else if (input == 1) {
result = 2;
} else {
result = 3;
}
return result;
Inni używają map:
var input = X;
var resultMap = Map.of(0, 1, 1, 2);
return resultMap.getOrDefault(input, 3);
Nie musisz już nadużywać kolekcji, aby ukryć dziury w składni języka!
var input = X;
return switch (input) {
case 0 -> 1;
case 1 -> 2;
default -> 3;
}
Czysto, precyzyjnie, czytelnie.
Dopasowanie wzorców
Czym do cholery jest „dopasowanie wzorców”? Oznacza to, że nie musisz już nadużywać okrągłych nawiasów.
Jeżeli posiadasz obiekt nieznanego typu, co zawsze jest mocno przerażające w Javie, musisz go zrzutować, aby uzyskać dostęp do jego metod i pól. Czasami masz do czynienia z bibliotekami zewnętrznymi, które dają ci prosty obiekt i można tylko zgadywać, co mieli na myśli.
void myMethod(Object input) {
//Who the hell are you, input - show yourself!!!
if(input instanceof Car && ((Car)input).type() == LAMBO) {
var lambo = (Car) input;
//now I can use lambo as an instance of Car and then throw this computer out of the window!
}
}
Dość paskudna sprawa. Cóż, teraz w Javie 17 możemy zrobić coś znacznie przyjemniejszego:
void myMethod(Object input) {
//Who the hell are you, input - show yourself!!!
if(input instanceof Car car && car.type() == LAMBO) {
car.wroomWroom(); // I can use a car as an instance of Car in the current scope and then drink some beer to celebrate my promotion to Senior Engineer!
} else {
// no car here
System.out.println("I'm an Object. I have no personality.");
}
}
input instanceof Car car
jest dopasowaniem wzorca — teraz kompilator automatycznie rozpozna zmienną car
jako instancję klasy Car.
Rekordy
Lubię rekordy. Od razu zacząłem ich używać jako komponentów Springa!
Pamiętasz jeszcze to?
class IJustNeedAValuePlease {
private final String name;
private final String surname;
IJustNeedAValuePlease(String name, String surname){
this.name = name;
this.surname = surname;
}
public String getName(){
return name;
}
public String getSurname(){
return surname;
}
}
Tyle wysiłku, aby stworzyć Tuple. To takie irytujące!
Wtedy na ratunek przyszedł Lombok:
@Getter
class IJustNeedAValuePlease {
private final String name;
private final String surname;
}
No proszę! Java posuwa się o krok dalej:
record AValueMate(String name, String surname){}
Teraz mamy niemutowalny, jednolinijkowy kontener danych. O wiele lepiej. Ja używam go również w Springu w konstruktorze DI.
@Service
record MyService(
AnotherService service /*Injected straight up*/
){}
Kilka nowych metod i klas
Możesz zajrzeć tutaj https://docs.oracle.com/en/java/javase/17/docs/api/new-list.html. Już nadużywam skrótu do konwersji Stream na Listę:
var list = stream.toList();
// stream.collect(Collectors.toList()) in Java 11.
Typy zapieczętowane
Teraz możesz sprawić, że ludzie będą szanować Twój kod! Teraz możesz kontrolować swoją hierarchię. Teraz nikt nie będzie dotykał twoich cennych interfejsów.
Załóżmy, że chcesz stworzyć taką kolekcję:
Ale chcesz także upewnić się, że te 3 modele będą jedynymi, które trafią na Twój “parking”!
public sealed class CarParkCar permits BlackCab, WhiteVain, BMW { ... }
Definiujesz swoją hierarchię na poziomie kompilatora. Jedna zapieczętowana klasa z dokładnie trójką legalnych dzieci. Jeśli ktoś namiesza w hierarchii, to kompilator nie pozwoli skompilować kodu! Świetne, jednak wciąż muszę znaleźć sposób, w jaki można by to wykorzystać.
Architektura ARM
Java działa również z nowym komputerem Mac M1. Tego faktu nie mogę za bardzo brać pod uwagę, ponieważ nie zamierzam wydawać miesięcznej pensji na laptopa, więc zostaję na Intelu, dopóki nie spłonie w odmętach piekieł.
Oryginał tekstu w języku angielskim przeczytasz tutaj.