Informacja: ten artykuł został pierwotnie opublikowany 22 października 2021 r. Jednak w grudniu 2022 r. został zaktualizowany o nowe informacje dotyczące pakietu Oracle Enterprise Performance Pack dla Java 8. Warto również zauważyć, że choć Java 17 przyniosła mnóstwo przydatnych i ciekawych nowości, Oracle opublikował już nową wersję LTS – wersję 21. Sprawdź nasz artykuł o nowościach w Java 21, jeśli chcesz wiedzieć, co oferuje ta wersja.
[Uwaga] Ten artykuł został pierwotnie przygotowany w języku angielskim i został przetłumaczony na język polski.
W marcu 2022 r. Java 8 utraciła wsparcie Oracle Premier Support. Nie oznacza to, że nie będzie już otrzymywać żadnych nowych aktualizacji, ale wysiłek Oracle wkładany w jej utrzymanie będzie prawdopodobnie znacznie mniejszy niż obecnie.
To oznacza, że istnieje dobry powód, aby przejść na nowszą wersję. Zwłaszcza że 14 września 2021 r. wydano Javę 17. Jest to nowa wersja Long Term Support (LTS), ze wsparciem Oracle Premier Support trwającym (co najmniej) do września 2026 r.. Co przynosi Java 17? Jak trudna będzie migracja? Czy warto? Spróbuję odpowiedzieć na te pytania w tym artykule.
Warto również zauważyć, że Java 8 wciąż otrzymuje pewne rozszerzenia – choć tylko dla wersji Oracle Java i w ramach kosztownej subskrypcji Java SE. 19 lipca 2022 r. wydano pakiet Oracle Enterprise Performance Pack dla Java 8. Numer wersji to 8u345-PERF-b31, a pełną listę zmian można znaleźć tutaj. Dodatki do tej wersji zostaną wspomniane w dalszej części artykułu przy porównywaniu poszczególnych funkcji Java 8 i 17.
Jeśli interesują Cię nowsze wersje Javy, mój kolega Arek Rosłoniec napisał dwa artykuły: o nowościach w Java 21 oraz o nowościach w Java 23.

Przyjrzyjmy się niektórym funkcjom.
Java 8, wydana w marcu 2014 r., jest obecnie używana przez 69% programistów w ich głównej aplikacji. Dlaczego po ponad 7 latach wciąż jest to najczęściej używana wersja? Przyczyn jest wiele.
Java 8 dostarczyła mnóstwo funkcji językowych, które sprawiły, że programiści Java chcieli porzucić poprzednie wersje. Lambdy, strumienie (streams), programowanie funkcyjne, rozbudowane rozszerzenia API – nie wspominając o MetaSpace czy rozszerzeniach G1. To była ta wersja Javy, której należało używać.
Java 9 pojawiła się 3 lata później, we wrześniu 2017 r., i dla typowego programisty nie zmieniła niemal nic. Nowy klient HTTP, Process API, drobne ulepszenia operatora diamentowego i try-with-resources.
Owszem, Java 9 przyniosła jedną znaczącą, a wręcz przełomową zmianę – projekt Jigsaw. Zmienił on bardzo, bardzo wiele rzeczy – ale wewnętrznie. Modularyzacja Javy daje ogromne możliwości, rozwiązuje wiele problemów technicznych i dotyczy każdego, ale tylko stosunkowo niewielka grupa użytkowników faktycznie potrzebowała głęboko zrozumieć te zmiany. Ze względu na nowości wprowadzone w Jigsaw wiele bibliotek wymagało dodatkowych modyfikacji, wydawano nowe wersje, a niektóre z nich nie działały poprawnie.
Migracja na Javę 9 – zwłaszcza w przypadku dużych, korporacyjnych aplikacji – była często trudna, czasochłonna i powodowała problemy z regresją. Po co więc to robić, skoro zysk jest niewielki, a kosztuje to mnóstwo czasu i pieniędzy?
Java Development Kit 17 (JDK 17) został wydany w październiku 2021 r. Czy to dobry moment, by odejść od ośmioletniej Javy 8? Najpierw zobaczmy, co oferuje Java 17. Co przynosi programiście, administratorowi czy SRE w porównaniu do Javy 8?
W tym artykule opisuję tylko te zmiany, które uznałem za wystarczająco ważne lub interesujące. To nie wszystko, co zostało zmienione, ulepszone i zoptymalizowane w ciągu lat ewolucji Javy. Jeśli chcesz zobaczyć pełną listę zmian w JDK, powinieneś wiedzieć, że są one śledzone jako JEP-y (JDK Enhancement Proposals). Listę można znaleźć w JEP-0.
Jeśli natomiast chcesz porównać API Javy między wersjami, istnieje świetne narzędzie o nazwie Java Version Almanac. Do API Javy dodano wiele przydatnych, drobnych elementów i sprawdzenie tej strony jest najlepszą opcją dla kogoś, kto chce poznać je wszystkie.
Na razie przeanalizujmy zmiany i nowe funkcje w każdej iteracji Javy, które są najważniejsze z perspektywy większości z nas, programistów Java.
Dodano nowe słowo kluczowe var, które pozwala na deklarowanie zmiennych lokalnych w bardziej zwięzły sposób. Spójrz na ten kod:
// sposób z Java 8 Map<String, List<MyDtoType>> myMap = new HashMap<String, List<MyDtoType>>(); List<MyDomainObjectWithLongName> myList = aDelegate.fetchDomainObjects(); // sposób z Java 10 var myMap = new HashMap<String, List<MyDtoType>>(); var myList = aDelegate.fetchDomainObjects()
Używając var, deklaracja jest znacznie krótsza i być może nieco bardziej czytelna niż wcześniej. Należy jednak pamiętać o czytelności – w niektórych przypadkach ukrywanie typu przed programistą może być błędem. Pamiętaj o właściwym nazywaniu zmiennych.
Niestety nie jest możliwe przypisanie lambdy do zmiennej za pomocą słowa kluczowego var:
// powoduje błąd kompilacji: // method reference needs an explicit target-type var fun = MyObject::mySpecialFunction;
Możliwe jest jednak użycie var w wyrażeniach lambda. Spójrz na poniższy przykład:
boolean isThereAneedle = stringsList.stream() .anyMatch((@NonNull var s) -> s.equals(“needle”));
Używając var w argumentach lambdy, możemy dodawać do nich adnotacje.
Można powiedzieć, że rekordy są odpowiedzią Javy na Lombok. Przynajmniej częściowo. Rekord to typ zaprojektowany do przechowywania danych. Pozwolę sobie zacytować fragment JEP 395, który dobrze to opisuje:
[…] rekord automatycznie zyskuje wiele standardowych elementów:
Innymi słowy, jest to z grubsza odpowiednik @Value z Lomboka. Pod względem językowym przypomina nieco enum. Jednak zamiast deklarować możliwe wartości, deklarujesz pola. Java generuje kod na podstawie tej deklaracji i potrafi go obsłużyć w lepszy, zoptymalizowany sposób. Podobnie jak enum, rekord nie może rozszerzać ani być rozszerzanym przez inne klasy, ale może implementować interfejsy oraz posiadać statyczne pola i metody. W przeciwieństwie do enum, rekord można instancjonować słowem kluczowym new.
Rekord może wyglądać tak:
record BankAccount (String bankName, String accountNumber) implements HasAccountNumber {}
I to wszystko. Całkiem krótko. Krótko znaczy dobrze!
Wszelkie automatycznie generowane metody mogą być zadeklarowane ręcznie przez programistę. Można również zadeklarować zestaw konstruktorów. Co więcej, w konstruktorach wszystkie pola, które są wyraźnie nieprzypisane, są niejawnie przypisywane do odpowiadających im parametrów konstruktora. Oznacza to, że przypisanie można całkowicie pominąć w konstruktorze!
record BankAccount (String bankName, String accountNumber) implements HasAccountNumber {
public BankAccount { // <-- to jest konstruktor! brak () !
if (accountNumber == null || accountNumber.length() != 26) {
throw new ValidationException(“Account number invalid”);
}
// przypisanie nie jest tutaj konieczne!
}
}
Wszystkie szczegóły, takie jak formalna gramatyka, uwagi dotyczące użytkowania i implementacji, znajdziesz w JEP 359.
Switch jest obecny w wielu językach, ale przez lata stawał się coraz mniej użyteczny ze względu na swoje ograniczenia. Inne części Javy ewoluowały, switch nie. Obecnie przypadki switch mogą być grupowane znacznie łatwiej i w bardziej czytelny sposób (zauważ, że nie ma słowa break!), a samo wyrażenie switch faktycznie zwraca wynik.
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
boolean freeDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> false;
case SATURDAY, SUNDAY -> true;
};
Jeszcze więcej można osiągnąć dzięki nowemu słowu kluczowemu yield, które pozwala na zwrócenie wartości z wnętrza bloku kodu. Jest to właściwie return, który działa wewnątrz bloku case i ustawia tę wartość jako wynik całego switcha. Może on również przyjmować wyrażenie zamiast pojedynczej wartości. Spójrzmy na przykład:
DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
boolean freeDay = switch (dayOfWeek) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> {
System.out.println("Praca, praca, praca");
yield false;
}
case SATURDAY, SUNDAY -> {
System.out.println("Jej, wolny dzień!");
yield true;
}
};
Choć nie jest to zmiana rewolucyjna, moim zdaniem instanceof rozwiązuje jeden z bardziej irytujących problemów języka Java. Czy kiedykolwiek musiałeś używać takiej składni?
if (obj instanceof MyObject) {
MyObject myObject = (MyObject) obj;
// … dalsza logika
}
Teraz już nie będziesz musiał. Java potrafi teraz utworzyć zmienną lokalną wewnątrz if, w ten sposób:
if (obj instanceof MyObject myObject) {
// … ta sama logika
}
To tylko jedna usunięta linia, ale była ona całkowicie zbędna z punktu widzenia przepływu kodu. Co więcej, zadeklarowana zmienna może być użyta w tym samym warunku if:
if (obj instanceof MyObject myObject && myObject.isValid()) {
// … ta sama logika
}
To trudniejsza do wyjaśnienia funkcja. Zacznijmy od tego – czy ostrzeżenie „no default” w switchu kiedykolwiek Cię irytowało? Uwzględniłeś wszystkie opcje akceptowane przez domenę, ale ostrzeżenie wciąż tam było. Klasy uszczelnione pozwalają pozbyć się takich ostrzeżeń przy sprawdzaniu typów instanceof .
Jeśli masz hierarchię taką jak ta:
public abstract sealed class Animal
permits Dog, Cat {
}
public final class Dog extends Animal {
}
public final class Cat extends Animal {
}
Będziesz teraz mógł zrobić coś takiego:
if (animal instanceof Dog d) {
return d.hauHau();
}
else if (animal instanceof Cat c) {
return c.miau();
}
I nie otrzymasz ostrzeżenia. Pozwól, że ujmę to inaczej: jeśli otrzymasz ostrzeżenie przy podobnej sekwencji, to ostrzeżenie będzie znaczące! A więcej informacji to zawsze dobra rzecz.
Mam mieszane uczucia co do tej zmiany. Wprowadzanie cyklicznych referencji nie wydaje się dobrą praktyką. Gdybym użył tego w kodzie produkcyjnym, starałbym się ukryć to gdzieś głęboko i nigdy nie pokazywać światu zewnętrznemu – mam na myśli nieeksponowanie tego przez API.
Deklarowanie długich ciągów znaków nie zdarza się często w programowaniu Java, ale kiedy już się zdarzy, jest męczące i mylące. Java 13 wprowadziła na to sposób, ulepszony w późniejszych wydaniach. Wieloliniowy blok tekstu można teraz zadeklarować następująco:
String myWallOfText = ””” ______ _ _ | ___ \ | | (_) | |_/ / __ ___| |_ _ _ _ ___ | __/ '__/ _ \ __| | | | / __| | | | | | __/ |_| | |_| \__ \ \_| |_| \___|\__|_|\__,_|___/ ”””
Nie ma potrzeby „uciekania z” (escaping) cudzysłowów ani znaków nowej linii. Można jednak „uciec” nową linię i zachować ciąg w jednej linii:
String myPoem = ””” Róże są czerwone, fiołki są niebieskie - Pretius robi najlepszy software, to jasne jak słońce ”””
Co jest odpowiednikiem:
String myPoem = ”Róże są czerwone, fiołki są niebieskie - Pretius robi najlepszy soft, to jasne jak słońce”.
Bloki tekstu mogą być używane do przechowywania w miarę czytelnych szablonów JSON lub XML w kodzie. Pliki zewnętrzne nadal są prawdopodobnie lepszym pomysłem, ale to miła opcja, by zrobić to w czystej Javie, jeśli zajdzie potrzeba.
Zdarzyło mi się kiedyś mieć taki łańcuch wywołań w aplikacji. Myślę, że Tobie również może wydać się znajomy:
company.getOwner().getAddress().getCity();
I otrzymałem NPE, który mówił mi dokładnie, w której linii napotkano null. Tak, to była ta linia. Bez debuggera nie mogłem stwierdzić, który obiekt był nullem, a raczej, która operacja wywołania (invoke) faktycznie spowodowała problem. Teraz wiadomość będzie konkretna i powie nam, że JVM „cannot invoke Person.getAddress()”.
Właściwie jest to bardziej zmiana w JVM niż w samej Javie – ponieważ analiza bajtkodu w celu zbudowania szczegółowego komunikatu jest wykonywana w czasie wykonywania przez JVM – ale bardzo przemawia ona do programistów.
Istnieje wiele bibliotek, które robią to samo, ale miło jest mieć porządnego klienta HTTP w samej Javie. Dobre wprowadzenie do nowych API można znaleźć w serwisie Baeldung.
Metoda get() na obiekcie Optional służy do pobrania wartości. Jeśli wartości nie ma, metoda rzuca wyjątek. Tak jak w poniższym kodzie.
MyObject myObject = myList.stream() .filter(MyObject::someBoolean) .filter((b) -> false) .findFirst() .get();
Java 10 wprowadziła nową metodę w Optional, o nazwie orElseThrow(). Co ona robi? Dokładnie to samo! Ale rozważ zmianę czytelności dla programisty.
MyObject myObject = myList.stream() .filter(MyObject::someBoolean) .filter((b) -> false) .findFirst() .orElseThrow();
Teraz programista dokładnie wie, co się stanie, gdy obiekt nie zostanie znaleziony. W rzeczywistości zaleca się używanie tej metody zamiast prostej – choć wszechobecnej – metody get().
Szkoda słów, oto kod. Pogrubione zostały nowości.
// odwrócenie Predicate, będzie jeszcze krótsze przy imporcie statycznym
collection.stream()
.filter(Predicate.not(MyObject::isEmpty))
.collect(Collectors.toList());
// String też dostał nowe rzeczy
“\nPretius\n rules\n all!”.repeat(10).lines().
.filter(Predictions.not(String::isBlank))
.map(String::strip)
.map(s -> s.indent(2))
.collect(Collectors.toList());
// nie trzeba przekazywać instancji tablicy jako argumentu
String[] myArray= aList.toArray(String[]::new);
// szybkie czytanie i pisanie do plików!
// pamiętaj jednak o łapaniu wszystkich możliwych wyjątków
Path path = Files.writeString(myFile, "Pretius Rules All !");
String fileContent = Files.readString(path);
// .toList() bezpośrednio na stream()
String[] arr={"a", "b", "c"};
var list = Arrays.stream(arr).toList();

Project Jigsaw wywrócił niektóre rzeczy do góry nogami, ale teraz wszystko działa dobrze.
Projekt Jigsaw wprowadzony w JDK 9 znacząco zmienił wnętrze maszyny wirtualnej Java (JVM). Zmienił on zarówno JLS (Java Language Specification), jak i JVMS (Java Virtual Machine Specification), dodał kilka JEP-ów (lista dostępna pod linkiem powyżej) i, co najważniejsze, wprowadził zmiany naruszające kompatybilność (breaking changes), które nie były zgodne z poprzednimi wersjami Javy.
Wprowadzono moduły Java 9 jako dodatkowy, najwyższy poziom organizacji plików JAR i klas. Istnieje mnóstwo materiałów wprowadzających do tego tematu, takich jak ten na Baeldung lub te slajdy autorstwa Yuichi Sakuraba.
Zyski były znaczące, choć niewidoczne gołym okiem. Tak zwane JAR hell przestało istnieć (byłeś tam? ja tak… i to było naprawdę piekło), choć teraz realną możliwością stało się module hell.
Z punktu widzenia typowego programisty zmiany te są teraz niemal niewidoczne. Tylko największe i najbardziej złożone projekty mogą w jakiś sposób odczuć ich skutki. Nowe wersje niemal wszystkich powszechnie używanych bibliotek przestrzegają nowych zasad i uwzględniają je wewnętrznie.
Począwszy od Javy 9, G1 jest domyślnym odśmiecaczem pamięci. Skraca on czasy pauz w porównaniu do Parallel GC, choć może mieć nieco niższą ogólną przepustowość. Przeszedł on szereg zmian, odkąd stał się domyślny, w tym zyskał możliwość zwracania nieużywanej przydzielonej pamięci do systemu operacyjnego (JEP 346).
W Javie 11 wprowadzono odśmiecacz ZGC, który osiągnął status produkcyjny w Javie 15 (JEP 377). Jego celem jest jeszcze większa redukcja przestojów. Od Javy 13 potrafi on również zwracać nieużywaną pamięć do systemu (JEP 351).
Kolejnym rozwiązaniem jest Shenandoah GC, wprowadzony w JDK 14 i uznany za gotowy do użytku produkcyjnego w Javie 15 (JEP 379). Dąży on do utrzymania krótkich czasów pauz, niezależnie od wielkości sterty (heap).
Warto zauważyć, że w Javie 8 wybór był znacznie mniejszy i jeśli nie zmieniłeś GC ręcznie, prawdopodobnie nadal używałeś Parallel GC. Samo przejście na Javę 17 może sprawić, że Twoja aplikacja będzie działać szybciej i mieć bardziej przewidywalne czasy wykonywania metod. Przejście na ZGC lub Shenandoah może dać jeszcze lepsze rezultaty.
Na koniec warto wspomnieć o nowym No-Op Garbage Collector (JEP 318), choć jest to funkcja eksperymentalna. Ten mechanizm właściwie nic nie robi – co pozwala na precyzyjny pomiar wykorzystania pamięci przez aplikację. Przydatne, jeśli chcesz zredukować narzut operacji pamięciowych do minimum.
Jeśli chcesz dowiedzieć się więcej o dostępnych opcjach, polecam świetną serię artykułów autorstwa Marko Topolnika, która porównuje poszczególne GC.
Wspomniany odśmiecacz G1 został dodany do Oracle Java 8 w wersji 8u345 pakietu Oracle Enterprise Performance Pack. Wraz z Compact Strings, może on znacząco wpłynąć na zużycie pamięci przez aplikacje Java.
Możesz tego nie wiedzieć, ale był czas, kiedy Java nie była świadoma tego, że działa w kontenerze. Nie brała pod uwagę ograniczeń pamięci kontenera i zamiast tego odczytywała dostępną pamięć systemu. Gdy miałeś maszynę z 16 GB RAM, ograniczyłeś kontener do 1 GB i uruchomiłeś w nim aplikację Java, często kończyło się to błędem, ponieważ JVM próbowała alokować więcej pamięci, niż faktycznie oferował kontener. Świetny artykuł Carlosa Sancheza wyjaśnia to szczegółowo.
Te problemy to już przeszłość. Od Javy 10 integracja z kontenerami jest domyślnie włączona. Może to jednak nie być dla Ciebie zauważalna zmiana, ponieważ poprawkę wprowadzono również w Java 8 update 131, choć wymagało to włączenia opcji eksperymentalnych i użycia flagi -XX:+UseCGroupMemoryLimitForHeap.
PS: Często dobrym pomysłem jest jawne określenie maksymalnej pamięci dla Javy za pomocą parametru -Xmx. W takich przypadkach problem z kontenerami nie występuje.
W ramach starań o szybszy start JVM, archiwa CDS (Class Data Sharing) przeszły wiele zmian od czasu wydania Javy 8. Począwszy od JDK 12, tworzenie archiwów CDS podczas procesu budowania jest domyślnie włączone (JEP 341). Ulepszenie w JDK 13 (JEP 350) umożliwiło aktualizację archiwów po każdym uruchomieniu aplikacji.
Class Data Sharing zostało również zaimplementowane dla Javy 8 w pakiecie Oracle Enterprise Performance Pack w wersji 8u345. Nie jest jednak jasne, jak głębokie są te zmiany; opis sugeruje, że dodano jedynie zakres objęty przez JEP 310. Nie udało mi się jednak tego potwierdzić.
Świetny artykuł Nicolaia Parloga pokazuje, jak użyć tej funkcji, by skrócić czas uruchamiania Twojej aplikacji.
Java Flight Recorder (JEP 328) pozwala na monitorowanie i profilowanie działającej aplikacji Java przy bardzo niskim (docelowo 1%) narzucie wydajnościowym. Java Mission Control umożliwia pobieranie i wizualizację danych z JFR. Zajrzyj do poradnika Baeldung, aby dowiedzieć się, jak z tego korzystać i co można dzięki temu zyskać.
Krótko mówiąc: tak, powinieneś. Jeśli posiadasz dużą, mocno obciążoną aplikację korporacyjną i wciąż używasz Javy 8, po migracji z pewnością zauważysz lepszą wydajność, szybszy start i mniejsze zużycie pamięci. Programiści pracujący nad aplikacją również będą zadowoleni dzięki licznym usprawnieniom w samym języku.
Koszt takiej operacji jest jednak trudny do oszacowania i różni się znacznie w zależności od używanych serwerów aplikacji, bibliotek oraz złożoności samej aplikacji (a właściwie liczby niskopoziomowych funkcji, których używa lub które reimplementuje).
Jeśli Twoje aplikacje to mikrousługi, prawdopodobnie wystarczy zmienić bazowy obraz Docker na 17-alpine, wersję kodu w Maven na 17 i wszystko powinno działać poprawnie. Niektóre aktualizacje frameworków lub bibliotek mogą się przydać (ale i tak robisz je okresowo, prawda?).
Wszystkie popularne serwery i frameworki posiadają już wsparcie dla projektu Jigsaw z Javy 9. Jest ono gotowe do użytku produkcyjnego, zostało solidnie przetestowane i poprawione przez lata. Wiele produktów oferuje przewodniki migracji lub przynajmniej obszerne informacje o wydaniu dla wersji kompatybilnych z Javą 9. Zobacz ciekawy artykuł od OSGI lub informacje o wydaniu Wildfly 15 wspomominające o wsparciu dla modułów.
Jeśli używasz Spring Boot, dostępnych jest wiele artykułów z poradami dotyczącymi migracji, jak ten w wiki spring-boot, ten na Baeldung lub jeszcze inny na DZone. Znajdziesz też interesujące studium przypadku na InfoQ. Migracja ze Spring Boot 1 na Spring Boot 2 to oddzielny temat, który również warto rozważyć. Istnieje oficjalny poradnik od Spring Boota oraz artykuł na Baeldung na ten temat.
Jeśli Twoja aplikacja nie posiadała własnych classloaderów, nie polegała mocno na klasie Unsafe ani na bibliotekach sun.misc czy sun.security – prawdopodobnie wszystko będzie w porządku. Skorzystaj z tego artykułu o narzędziu JDEP (Java Dependency Analysis Tool), aby dowiedzieć się o zmianach, które być może będziesz musiał wprowadzić.
Niektóre elementy zostały usunięte z Javy od wersji 8, m.in. silnik Nashorn JS, API i narzędzia Pack200, porty Solaris/Sparc, kompilatory AOT i JIT oraz moduły Java EE i Corba. Niektóre rzeczy wciąż pozostają, ale są oznaczone jako przestarzałe (deprecated), jak Applet API czy Security Manager. Skoro istnieją ważne powody ich usunięcia, i tak powinieneś rozważyć rezygnację z nich w swojej aplikacji.
Zapytałem liderów technicznych w Pretius o ich doświadczenia z migracjami z Java 8 na Java 9+. Padło kilka przykładów i żaden nie był problematyczny. Tu biblioteka nie działała i wymagała aktualizacji, tam potrzebna była dodatkowa konfiguracja, ale ogólnie nie było to wcale złe doświadczenie.
Java 17 LTS będzie wspierana przez lata. Z drugiej strony, wsparcie dla Javy 8 dobiegło końca. To z pewnością solidny powód, by rozważyć przejście na nową wersję Javy. W tym artykule omówiłem najważniejsze zmiany w języku i JVM między wersjami 8 i 17, aby łatwiej było zrozumieć różnice między nimi, a także ocenić ryzyko i korzyści płynące z migracji.
Jeśli podejmujesz decyzje w swojej firmie, zadaj sobie pytanie: czy kiedykolwiek będzie „dobry czas”, aby zostawić Javę 8 za sobą? Zawsze trzeba będzie wydać jakieś pieniądze, poświęcić czas i zawsze będzie istniało ryzyko dodatkowej pracy. Skoro nigdy nie ma „idealnego momentu”, teraz jest prawdopodobnie tak dobry moment, jak żaden inny.
Pretius posiada świetny zespół programistów Java i duże doświadczenie w wykorzystywaniu tej technologii w systemach klasy enterprise. Znamy się również na wielu różnych branżach. Potrzebujesz oprogramowania opartego na Javie? Napisz do nas na adres hello@pretius.com (lub skorzystaj z poniższego formularza). Odezwiemy się w ciągu 48 godzin. Możesz również sprawdzić moje inne artykuły na blogu Pretius:
Java 8 została wydana w marcu 2014 roku.
Java 17 została wydana 15 września 2021 roku.
Najnowszą wersją Javy jest obecnie Java 23 (stan na koniec 2024 r.). Jednak najnowszą wersją z długoterminowym wsparciem (LTS) jest Java 21 (i Java 17 przed nią).
Możesz sprawdzić swoją obecną wersję Javy w sekcji Informacje (About) w Panelu Sterowania Java lub wpisując polecenie w terminalu:
java -version
Instalacja oprogramowania sprowadza się do prostego uruchomienia pliku wykonywalnego (executable), ale przygotowanie systemu na tę zmianę może być bardziej skomplikowane.
JDK 17 to duża aktualizacja Javy z mnóstwem usprawnień i nowości. Oferuje następujące funkcje:
Java 17 to wersja z długim wsparciem (long-term support) – będzie wspierana przez co najmniej osiem lat. Java 18 z kolei to mniejsza aktualizacja z kilkoma dodatkowymi funkcjami i jedynie 6-miesięcznym wsparciem.
Tak, podobnie jak wszystkie wersje JDK, JDK 17 zawiera Java 17 JRE.
To płatna subskrypcja, którą można wykupić, aby przenieść niektóre funkcje Javy 17 – takie jak garbage collector G1 – do Javy 8.