Udostępnij za pośrednictwem


Przejście z języka Java 8 do środowiska Java 11

Nie ma jednego uniwersalnego rozwiązania do przejścia kodu z języka Java 8 do języka Java 11. W przypadku aplikacji innej niż trywialna przejście z języka Java 8 do środowiska Java 11 może być znaczną ilością pracy. Potencjalne problemy obejmują usunięte interfejsy API, przestarzałe pakiety, korzystanie z wewnętrznego interfejsu API, zmiany modułów ładujących klasy i zmiany w usuwaniu elementów bezużytecznych.

Ogólnie rzecz biorąc, są dwa podejścia: próba uruchomienia na Java 11 bez ponownego kompilowania albo najpierw kompilowanie przy użyciu JDK 11. Jeśli celem jest jak najszybsze uruchomienie aplikacji, po prostu próba uruchomienia w środowisku Java 11 jest często najlepszym rozwiązaniem. W przypadku biblioteki celem będzie opublikowanie artefaktu skompilowanego i przetestowanego przy użyciu zestawu JDK 11.

Przejście do środowiska Java 11 jest warte wysiłku. Dodano nowe funkcje i wprowadzono ulepszenia od języka Java 8. Te funkcje i ulepszenia zwiększają uruchamianie, wydajność, użycie pamięci i zapewniają lepszą integrację z kontenerami. Ponadto istnieją dodatki i modyfikacje interfejsu API, które zwiększają produktywność deweloperów.

Ten dokument dotyczy narzędzi do sprawdzania kodu. Obejmuje również problemy, które można napotkać, i zalecenia dotyczące ich rozwiązywania. Należy również zapoznać się z innymi przewodnikami, takimi jak Oracle JDK Migration Guide ( Przewodnik po migracji zestawu Oracle JDK). Jak uczynić istniejący kod modularnym nie jest omówione tutaj.

Przybornik

Java 11 ma dwa narzędzia, jdeprscan i jdeps, które są przydatne do wykrywania potencjalnych problemów. Te narzędzia można uruchamiać na istniejących plikach klasy lub jar. Możesz ocenić nakład pracy przy przejściu bez konieczności ponownego kompilowania.

Program jdeprscan szuka użycia przestarzałych lub usuniętych funkcjonalności API. Użycie przestarzałego interfejsu API nie jest problemem blokującym, ale jest czymś, co należy zbadać. Czy istnieje zaktualizowany plik jar? Czy musisz zgłosić problem, aby rozwiązać kwestię użycia przestarzałego interfejsu API? Użycie usuniętego interfejsu API to problem blokujący, który należy rozwiązać przed próbą uruchomienia w środowisku Java 11.

jdeps, który jest analizatorem zależności klasy Java. W przypadku użycia z opcją --jdk-internalsjdeps informuje, która klasa zależy od wewnętrznego interfejsu API. Możesz nadal używać wewnętrznego interfejsu API w języku Java 11, ale zastąpienie użycia powinno być priorytetem. Strona wiki zestawu OpenJDK Java Dependency Analysis Tool zaleciła zastąpienie niektórych powszechnie używanych wewnętrznych interfejsów API zestawu JDK.

Istnieją wtyczki jdeps i jdeprscan zarówno dla narzędzi Gradle, jak i Maven. Zalecamy dodanie tych narzędzi do skryptów kompilacji.

Sam kompilator języka Java, javac, to inne narzędzie w przyborniku. Ostrzeżenia i błędy pochodzące z narzędzia jdeprscan i jdeps zostaną wycofane z kompilatora. Zaletą korzystania z narzędzi jdeprscan i jdeps jest możliwość uruchamiania tych narzędzi za pośrednictwem istniejących plików jar i plików klas, w tym bibliotek innych firm.

Czego jdeprscan i jdeps nie mogą zrobić, to ostrzec o użyciu odbicia do uzyskania dostępu do zamkniętego interfejsu API. Dostęp refleksyjny jest sprawdzany w czasie wykonywania. Ostatecznie musisz uruchomić kod w środowisku Java 11, aby wiedzieć z pewnością.

Korzystanie z narzędzia jdeprscan

Najprostszym sposobem użycia narzędzia jdeprscan jest nadanie mu pliku jar z istniejącej kompilacji. Można również nadać mu katalog, taki jak katalog wyjściowy kompilatora lub pojedyncza nazwa klasy. Użyj opcji --release 11, aby uzyskać najbardziej kompletną listę przestarzałych interfejsów API. Jeśli chcesz określić, które przestarzałe API priorytetyzować, cofnij ustawienie do --release 8. Interfejs API, który został oznaczony jako przestarzały w wersji Java 8, prawdopodobnie zostanie usunięty wcześniej niż interfejs API, który został niedawno oznaczony jako przestarzały.

jdeprscan --release 11 my-application.jar

Narzędzie jdeprscan generuje komunikat o błędzie, jeśli ma problem z rozwiązaniem klasy zależnej. Na przykład error: cannot find class org/apache/logging/log4j/Logger. Zaleca się dodawanie klas zależnych do --class-path lub użycie ścieżki klas aplikacji, ale narzędzie będzie kontynuować skanowanie bez niego. Argument to --class-path. Nie będą działać żadne inne odmiany argumentu ścieżki klasy.

jdeprscan --release 11 --class-path log4j-api-2.13.0.jar my-application.jar
error: cannot find class sun/misc/BASE64Encoder
class com/company/Util uses deprecated method java/lang/Double::<init>(D)V

Te dane wyjściowe informują nas, że klasa com.company.Util wywołuje przestarzały konstruktor klasy java.lang.Double. javadoc zaleci API do użycia zamiast przestarzałego API. Żaden wysiłek nie rozwiąże error: cannot find class sun/misc/BASE64Encoder, ponieważ jest to interfejs API, który został usunięty. Od Java 8, java.util.Base64 powinien być używany.

Uruchom jdeprscan --release 11 --list, aby zrozumieć, który interfejs API został wycofany od Java 8. Aby uzyskać listę usuniętych interfejsów API, uruchom polecenie jdeprscan --release 11 --list --for-removal.

Korzystanie z narzędzia jdeps

Użyj jdeps z opcją --jdk-internals, aby znaleźć zależności w wewnętrznych interfejsach API JDK. W tym przykładzie jest wymagana opcja --multi-release 11 wiersza polecenia, ponieważ log4j-core-2.13.0.jar jest plikiem jar z wieloma wersjami. Bez tej opcji narzędzie jdeps będzie zgłaszać problem, jeśli znajdzie plik JAR typu multi-release. Opcja określa, która wersja plików klasy ma być sprawdzana.

jdeps --jdk-internals --multi-release 11 --class-path log4j-core-2.13.0.jar my-application.jar
Util.class -> JDK removed internal API
Util.class -> jdk.base
Util.class -> jdk.unsupported
   com.company.Util        -> sun.misc.BASE64Encoder        JDK internal API (JDK removed internal API)
   com.company.Util        -> sun.misc.Unsafe               JDK internal API (jdk.unsupported)
   com.company.Util        -> sun.nio.ch.Util               JDK internal API (java.base)

Warning: JDK internal APIs are unsupported and private to JDK implementation that are
subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependence on any JDK internal APIs.
For the most recent update on JDK internal API replacements, please check:
https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool

JDK Internal API                         Suggested Replacement
----------------                         ---------------------
sun.misc.BASE64Encoder                   Use java.util.Base64 @since 1.8
sun.misc.Unsafe                          See http://openjdk.java.net/jeps/260   

Dane wyjściowe zawierają kilka dobrych porad dotyczących wyeliminowania użycia wewnętrznego interfejsu API zestawu JDK! Jeśli to możliwe, sugerowany jest zastępczy interfejs API. Nazwa modułu, w którym pakiet jest hermetyzowany, jest podana w nawiasach. Nazwa modułu może być używana z elementem --add-exports lub --add-opens , jeśli jest to konieczne, aby jawnie przerwać hermetyzację.

Użycie sun.misc.BASE64Encoder lub sun.misc.BASE64Decoder spowoduje błąd java.lang.NoClassDefFoundError w Java 11. Kod, który używa tych interfejsów API, musi zostać zmodyfikowany w celu używania java.util.Base64.

Spróbuj wyeliminować użycie dowolnego interfejsu API pochodzącego z modułu jdk.unsupported. Interfejs API z tego modułu będzie odwoływać się do propozycji ulepszenia zestawu JDK (JEP) 260 jako sugerowanego zastąpienia. W skrócie JEP 260 mówi, że użycie wewnętrznego interfejsu API będzie obsługiwane do momentu udostępnienia zastępczego interfejsu API. Mimo że kod może używać wewnętrznego interfejsu API zestawu JDK, będzie on nadal działać przez pewien czas. Zapoznaj się z JEP 260, ponieważ wskazuje na zamienniki dla niektórych wewnętrznych interfejsów API. Uchwyty zmiennych mogą być używane zamiast niektórych interfejsów API sun.misc.Unsafe , na przykład.

jdeps może robić więcej niż tylko skanować pod kątem użycia wewnętrznych elementów JDK. Jest to przydatne narzędzie do analizowania zależności i generowania plików informacji modułu. Zapoznaj się z dokumentacją , aby uzyskać więcej informacji.

Korzystanie z narzędzia javac

Kompilowanie przy użyciu zestawu JDK 11 będzie wymagać aktualizacji skryptów kompilacji, narzędzi, struktur testowych i dołączonych bibliotek. -Xlint:unchecked Użyj opcji javac, aby uzyskać szczegółowe informacje na temat korzystania z wewnętrznego interfejsu API zestawu JDK i innych ostrzeżeń. Może być również konieczne użycie --add-opens lub --add-reads w celu uwidocznienia hermetyzowanych pakietów dla kompilatora (zobacz JEP 261).

Biblioteki mogą rozważyć stworzenie pliku jar z wieloma wydaniami. Pliki jar z wieloma wersjami umożliwiają obsługę środowisk uruchomieniowych Java 8 i Java 11 z tego samego pliku jar. Dodają one złożoności do procesu budowy. Tworzenie plików JAR z wieloma wydaniami wykracza poza zakres tego dokumentu.

Uruchamianie w środowisku Java 11

Większość aplikacji powinna działać w środowisku Java 11 bez modyfikacji. Pierwszą rzeczą, którą należy spróbować, jest uruchomienie w środowisku Java 11 bez ponownego komplikowania kodu. Celem samego uruchomienia jest sprawdzenie, jakie ostrzeżenia i błędy pojawiają się podczas wykonania. Takie podejście uzyskuje
aplikacja uruchamiająca się szybciej na środowisku Java 11, koncentrując się na niezbędnym minimum.

Większość napotkanych problemów można rozwiązać bez konieczności ponownego kompilowania kodu. Jeśli problem musi zostać rozwiązany w kodzie, wprowadź poprawkę, ale kontynuuj kompilowanie przy użyciu zestawu JDK 8. Jeśli to możliwe, przygotować aplikację do uruchomienia z wersją 11 przed skompilowaniem jej za pomocą JDK 11.

Sprawdzanie opcji wiersza polecenia

Przed uruchomieniem w środowisku Java 11 wykonaj szybkie skanowanie opcji wiersza polecenia. Opcje, które zostały usunięte , spowodują zamknięcie maszyny wirtualnej Java (JVM). Ta kontrola jest szczególnie ważna, jeśli używasz opcji rejestrowania GC, ponieważ zostały one znacząco zmienione od Java 8. Narzędzie JaCoLine jest dobrym rozwiązaniem do wykrywania problemów z opcjami wiersza polecenia.

Sprawdzanie bibliotek innych firm

Potencjalnym źródłem problemów są biblioteki innych firm, których nie kontrolujesz. Możesz aktywnie aktualizować biblioteki innych firm do nowszych wersji. Możesz też zobaczyć, co wypada z uruchamiania aplikacji i zaktualizować tylko te biblioteki, które są niezbędne. Problem z aktualizowaniem wszystkich bibliotek do najnowszej wersji polega na tym, że utrudnia znalezienie głównej przyczyny, jeśli w aplikacji wystąpi błąd. Czy wystąpił błąd z powodu zaktualizowanej biblioteki? Czy też wystąpił błąd spowodowany przez pewną zmianę w środowisku uruchomieniowym? Problem z aktualizowaniem tylko tego, co jest konieczne, może wymagać kilku iteracji, aby rozwiązać problem.

W tym miejscu zaleca się wprowadzenie jak najmniejszej liczby zmian i zaktualizowanie bibliotek innych firm jako osobny wysiłek. Jeśli zaktualizujesz bibliotekę innej firmy, częściej niż nie potrzebujesz najnowszej i największej wersji zgodnej z językiem Java 11. W zależności od tego, jak bardzo w tyle jest twoja obecna wersja, możesz chcieć podjąć bardziej ostrożne podejście i zaktualizować do pierwszej wersji zgodnej z Java 9+.

Oprócz przeglądania informacji o wersji można użyć narzędzi jdeps i jdeprscan do oceny pliku jar. Ponadto grupa jakości OpenJDK utrzymuje stronę typu wiki quality outreach zawierającą listę stanu testowania wielu bezpłatnych projektów oprogramowania Open Source Software (FOSS) względem wersji zestawu OpenJDK.

Jawne ustawianie odzyskiwania pamięci

Równoległy zbieracz śmieci (Parallel GC) jest domyślnym GC w języku Java 8. Jeśli aplikacja używa wartości domyślnej, to GC powinien być jawnie ustawiony za pomocą opcji wiersza poleceń -XX:+UseParallelGC. Domyślna wartość została zmieniona w wersji Java 9 na zbieracz śmieci Garbage First (G1GC). Aby można było porównać aplikację działającą w środowisku Java 8 i Java 11, ustawienia GC muszą być takie same. Eksperymentowanie z ustawieniami GC powinno zostać odroczone do momentu zweryfikowania aplikacji w środowisku Java 11.

Jawne ustawianie opcji domyślnych

W przypadku uruchomienia na maszynie wirtualnej HotSpot ustawienie opcji -XX:+PrintCommandLineFlags wiersza polecenia spowoduje zrzut wartości opcji ustawionych przez maszynę wirtualną, szczególnie wartości domyślne ustawione przez GC. Uruchom z tą flagą w środowisku Java 8 i użyj wyświetlonych opcji podczas uruchamiania w środowisku Java 11. W większości przypadków wartości domyślne są takie same od wersji 8 do 11. Jednak użycie ustawień z poziomu 8 zapewnia parzystość.

Zalecane jest ustawienie opcji --illegal-access=warn wiersza polecenia. W środowisku Java 11 użycie refleksji w celu uzyskania dostępu do wewnętrznego API JDK spowoduje wyświetlenie ostrzeżenia o niedozwolonym reflektywnym dostępie. Domyślnie ostrzeżenie jest wystawiane tylko dla pierwszego nielegalnego dostępu. Ustawienie --illegal-access=warn spowoduje ostrzeżenie dotyczące każdego niedozwolonego dostępu refleksyjnego. Można znaleźć więcej przypadków niedozwolonego dostępu, gdy opcja jest ustawiona na ostrzeżenie. Ale otrzymasz również wiele nadmiarowych ostrzeżeń.
Po uruchomieniu aplikacji w środowisku Java 11 ustaw opcję --illegal-access=deny naśladując przyszłe zachowanie środowiska uruchomieniowego Java. Począwszy od języka Java 16, wartość domyślna to --illegal-access=deny.

KlasyLoader ostrzega

W języku Java 8 można rzutować klasowy ładowark systemowy na element URLClassLoader. Zwykle odbywa się to przez aplikacje i biblioteki, które chcą wstrzyknąć klasy do ścieżki klas w czasie wykonywania. Hierarchia modułu ładującego klasy została zmieniona w środowisku Java 11. Moduł ładujący klasy systemowej (znany również jako moduł ładujący klasy aplikacji) jest teraz klasą wewnętrzną. Rzutowanie na URLClassLoader spowoduje zgłoszenie ClassCastException w czasie wykonywania. Język Java 11 nie ma interfejsu API do dynamicznego rozszerzania ścieżki klas w czasie wykonywania, ale można to zrobić przez refleksję, z oczywistymi zastrzeżeniami dotyczącymi używania wewnętrznego interfejsu API.

W środowisku Java 11 moduł ładujący klasy rozruchowej ładuje tylko podstawowe moduły. Jeśli tworzysz moduł ładujący klasy z elementem nadrzędnym o wartości null, może nie znaleźć wszystkich klas platformy. W środowisku Java 11 należy przekazać ClassLoader.getPlatformClassLoader() zamiast null jako rodzica klas ładowanych w takich przypadkach.

Zmiany danych ustawień regionalnych

Domyślne źródło danych ustawień regionalnych w Java 11 zostało zaktualizowane wraz z JEP 252 na Wspólne Repozytorium Danych Lokalizacyjnych Konsorcjum Unicode. Może to mieć wpływ na zlokalizowane formatowanie. Ustaw właściwość systemową java.locale.providers=COMPAT,SPI, aby przywrócić zachowanie ustawień regionalnych Java 8, jeśli to konieczne.

Potencjalne problemy

Poniżej przedstawiono niektóre typowe problemy, które mogą wystąpić. Aby uzyskać więcej informacji na temat tych problemów, skorzystaj z linków.

Nierozpoznane opcje

Jeśli opcja wiersza polecenia została usunięta, aplikacja będzie wyświetlać Unrecognized option: lub Unrecognized VM option następujące po nazwie błędnej opcji. Nierozpoznana opcja spowoduje zamknięcie maszyny wirtualnej. Opcje, które zostały przestarzałe, ale nie zostały usunięte, spowodują wyświetlenie ostrzeżenia maszyny wirtualnej.

Ogólnie rzecz biorąc, opcje, które zostały usunięte, nie mają zastąpienia, a jedynym rozwiązaniem jest usunięcie opcji z wiersza polecenia. Wyjątkiem są opcje rejestrowania zbierania nieużytków. Rejestrowanie GC zostało ponownie wdrożone w środowisku Java 9, aby użyć ujednoliconej struktury rejestrowania JVM. Zapoznaj się z tematem "Tabela 2-2 Mapowanie starszych flag logowania rozliczania sterty do konfiguracji Xlog" w dziale Włączanie rejestrowania za pomocą ujednoliconego systemu rejestrowania JVM w dokumentacji narzędzi Java SE 11.

Ostrzeżenia maszyny wirtualnej

Użycie przestarzałych opcji spowoduje wyświetlenie ostrzeżenia. Opcja jest przestarzała, gdy została zamieniona lub nie jest już przydatna. Podobnie jak w przypadku opcji usuniętych, te opcje powinny zostać usunięte z wiersza polecenia. Ostrzeżenie VM Warning: Option <option> was deprecated oznacza, że opcja jest nadal obsługiwana, ale ta obsługa może zostać usunięta w przyszłości. Opcja, która nie jest już obsługiwana i wygeneruje ostrzeżenie VM Warning: Ignoring option. Opcje, które nie są już obsługiwane, nie mają wpływu na środowisko uruchomieniowe.

Na stronie internetowej Eksplorator opcji maszyny wirtualnej znajduje się wyczerpująca lista opcji, które zostały dodane do języka Java lub usunięte z niego od czasu JDK 7.

Błąd: Nie można utworzyć maszyny wirtualnej Java

Ten komunikat o błędzie jest wyświetlany, gdy maszyna JVM napotka nierozpoznaną opcję.

OSTRZEŻENIE: Wystąpiła niedozwolona operacja dostępu refleksyjnego

Gdy kod Java używa refleksji w celu uzyskania dostępu do wewnętrznego interfejsu API JDK, środowisko uruchomieniowe wyświetli ostrzeżenie o nielegalnym dostępie refleksyjnym.

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by my.sample.Main (file:/C:/sample/) to method sun.nio.ch.Util.getTemporaryDirectBuffer(int)
WARNING: Please consider reporting this to the maintainers of com.company.Main
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Oznacza to, że moduł nie wyeksportował pakietu, do którego jest uzyskiwany dostęp za pośrednictwem odbicia. Pakiet jest hermetyzowany w module i jest w zasadzie wewnętrznym interfejsem API. Ostrzeżenie można zignorować na początkowym etapie rozpoczynania pracy z Javą 11. Środowisko uruchomieniowe Java 11 zezwala na dostęp odzwierciedlający, dzięki czemu starszy kod może nadal działać.

Aby rozwiązać ten problem, poszukaj zaktualizowanego kodu, który nie korzysta z wewnętrznego interfejsu API. Jeśli problemu nie można rozwiązać za pomocą zaktualizowanego kodu, można użyć opcji wiersza polecenia --add-exports lub --add-opens w celu otwarcia dostępu do pakietu. Te opcje umożliwiają dostęp do nieeksportowanych typów jednego modułu z innego modułu.

Opcja --add-exports pozwala modułowi docelowemu uzyskać dostęp do publicznych typów pakietu o podanej nazwie w module źródłowym. Czasami kod będzie używał setAccessible(true) do uzyskiwania dostępu do niepublicznych elementów członkowskich i interfejsu API. Jest to nazywane głębokim odbiciem. W takim przypadku użyj --add-opens , aby przyznać kodowi dostęp do niepublicznych składników pakietu. Jeśli nie masz pewności, czy używać --add-exports, czy --add-opens, zacznij od --add-exports.

Opcje --add-exports lub --add-opens należy traktować jako obejście, a nie długoterminowe rozwiązanie. Użycie tych opcji łamie hermetyzację systemu modułów, który ma na celu uniemożliwienie używania wewnętrznego interfejsu API JDK. Jeśli wewnętrzny interfejs API zostanie usunięty lub zmieni się, aplikacja zakończy się niepowodzeniem. Dostęp refleksyjny zostanie zablokowany w środowisku Java 16, chyba że dostęp zostanie włączony za pomocą opcji wiersza polecenia, takich jak --add-opens. Aby naśladować przyszłe zachowanie, ustaw --illegal-access=deny w wierszu polecenia.

Ostrzeżenie w powyższym przykładzie jest wystawiane, ponieważ sun.nio.ch pakiet nie jest eksportowany przez java.base moduł. Innymi słowy, w pliku exports sun.nio.ch; modułu module-info.java nie ma java.base. Można rozwiązać ten problem za pomocą polecenia --add-exports=java.base/sun.nio.ch=ALL-UNNAMED. Klasy, które nie są zdefiniowane w module niejawnie należą do modułu bez nazwy , dosłownie o nazwie ALL-UNNAMED.

java.lang.reflect.InaccessibleObjectException

Ten wyjątek wskazuje, że próbujesz wywołać setAccessible(true) na polu lub metodzie zamkniętej klasy. Może pojawić się również ostrzeżenie o niedozwolonym odblaskowym dostępie. Użyj opcji --add-opens , aby przyznać kodowi dostęp do niepublicznych elementów członkowskich pakietu. Komunikat o wyjątku powie Ci, że moduł „nie otwiera” pakietu dla modułu, który próbuje wywołać setAccessible. Jeśli moduł jest "moduł bez nazwy", użyj UNNAMED-MODULE jako modułu docelowego w opcji --add-opens.

java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.ArrayList jdk.internal.loader.URLClassPath.loaders accessible: 
module java.base does not "opens jdk.internal.loader" to unnamed module @6442b0a6

$ java --add-opens=java.base/jdk.internal.loader=UNNAMED-MODULE example.Main

java.lang.NoClassDefFoundError

Błąd NoClassDefFoundError najprawdopodobniej jest spowodowany przez podzielony pakiet lub odwołując się do usuniętych modułów.

Błąd NoClassDefFoundError spowodowany przez tzw. "split-packages"

Pakiet podzielony jest wtedy, gdy pakiet znajduje się w więcej niż jednej bibliotece. Objawem problemu z pakietem podzielonym jest to, że klasa, którą znasz jako będącą na ścieżce klas, nie zostaje odnaleziona.

Ten problem będzie występować tylko w przypadku korzystania ze ścieżki modułu. System modułów Java optymalizuje wyszukiwanie klas, ograniczając pakiet do jednego nazwanego modułu. Środowisko uruchomieniowe zapewnia preferencję ścieżki modułu na ścieżce klasy podczas wyszukiwania klas. Jeśli pakiet jest podzielony między moduł i ścieżkę klasy, tylko moduł jest używany do wyszukiwania klas. Może to prowadzić do NoClassDefFound błędów.

Łatwym sposobem sprawdzenia, czy pakiet jest podzielony, jest podłączenie ścieżki modułu i ścieżki klasy do jdeps oraz użycie ścieżki do plików klas aplikacji jako ścieżki<>. Jeśli istnieje pakiet podzielony, jdeps wyświetli ostrzeżenie: Warning: split package: <package-name> <module-path> <split-path>.

Ten problem można rozwiązać za pomocą polecenia --patch-module <module-name>=<path>[,<path>] , aby dodać pakiet podzielony do nazwanego modułu.

Błąd NoClassDefFoundError spowodowany używaniem modułów Java EE lub CORBA

Jeśli aplikacja działa w środowisku Java 8, ale zgłasza element java.lang.NoClassDefFoundError lub java.lang.ClassNotFoundException, prawdopodobnie aplikacja korzysta z pakietu z modułów Java EE lub CORBA. Te moduły zostały wycofane w środowisku Java 9 i usunięte w środowisku Java 11.

Aby rozwiązać ten problem, dodaj zależność środowiska uruchomieniowego do projektu.

Usunięto moduł Pakiet, którego dotyczy problem Sugerowana zależność
API języka Java do usług sieciowych XML (JAX-WS) java.xml.ws Środowisko uruchomieniowe JAX WS RI
Architektura języka Java dla powiązania XML (JAXB) java.xml.bind Środowisko uruchomieniowe JAXB
JavaBeans Activation Framework (JAV) java.activation JavaBeans (TM) Activation Framework
Typowe adnotacje java.xml.ws.annotation Interfejs API adnotacji Javax
Architektura brokera żądań wspólnych obiektów (CORBA) java.corba GlassFish CORBA ORB
API transakcji Java (JTA) java.transaction Interfejs API transakcji Języka Java

-Xbootclasspath/p nie jest już obsługiwaną opcją

Obsługa programu -Xbootclasspath/p została usunięta. Użyj --patch-module zamiast tego. Opcja --patch-module jest opisana w specyfikacji JEP 261. Wyszukaj sekcję oznaczoną "Patching module content". --patch-module może być używany z językiem javac i językiem Java w celu zastąpienia lub rozszerzenia klas w module.

Co w efekcie robi --patch-module, to wstawienie modułu patch do wyszukiwania klas systemu modułów. System modułów najpierw pobierze klasę z modułu patch. Jest to taki sam efekt jak przed oczekiwaniem na ścieżkę bootclasspath w języku Java 8.

UnsupportedClassVersionError

Ten wyjątek oznacza, że próbujesz uruchomić kod skompilowany przy użyciu nowszej wersji języka Java we wcześniejszej wersji języka Java. Na przykład używasz środowiska Java 11 z plikiem jar skompilowanym przy użyciu zestawu JDK 13.

Wersja języka Java Wersja formatu pliku klasy
8 52
9 53
10 54
11 55
12 56
13 57

Dalsze kroki

Po uruchomieniu aplikacji w środowisku Java 11 rozważ przeniesienie bibliotek poza ścieżkę klasy i ścieżkę modułu. Wyszukaj zaktualizowane wersje bibliotek, od których zależy aplikacja. Wybierz biblioteki modułowe, jeśli są dostępne. Używaj ścieżki modułu tak często, jak to możliwe, nawet jeśli nie planujesz korzystania z modułów w aplikacji. Użycie ścieżki modułu zapewnia lepszą wydajność ładowania klas niż ścieżki klas.