Bagikan melalui


Transisi dari Java 8 ke Java 11

Tidak ada solusi satu ukuran untuk semua untuk kode transisi dari Java 8 ke Java 11. Untuk aplikasi yang tidak sepele, berpindah dari Java 8 ke Java 11 bisa menjadi sejumlah besar pekerjaan. Potensi masalah termasuk API yang dihapus, paket yang tidak digunakan lagi, penggunaan API internal, perubahan pada loader kelas, dan perubahan pada pengumpulan sampah.

Secara umum, pendekatannya adalah mencoba menjalankan pada Java 11 tanpa mengkompilasi ulang, atau untuk mengkompilasi dengan JDK 11 terlebih dahulu. Jika tujuannya adalah untuk membuat aplikasi aktif dan berjalan secepat mungkin, hanya mencoba menjalankan pada Java 11 sering kali merupakan pendekatan terbaik. Untuk pustaka, tujuannya adalah untuk menerbitkan artefak yang dikompilasi dan diuji dengan JDK 11.

Pindah ke Java 11 sepadan dengan upayanya. Fitur baru telah ditambahkan dan penyempurnaan telah dibuat sejak Java 8. Fitur dan penyempurnaan ini meningkatkan startup, performa, penggunaan memori, dan memberikan integrasi yang lebih baik dengan kontainer. Dan ada penambahan dan modifikasi pada API yang meningkatkan produktivitas pengembang.

Dokumen ini menyentuh alat untuk memeriksa kode. Ini juga mencakup masalah yang mungkin Anda temui dan rekomendasi untuk menyelesaikannya. Anda juga harus berkonsultasi dengan panduan lain, seperti Panduan Migrasi Oracle JDK. Cara membuat modular kode yang ada tidak tercakup di sini.

Kotak alat

Java 11 memiliki dua alat, jdeprscan dan jdeps, yang berguna untuk mengendus potensi masalah. Alat-alat ini dapat dijalankan terhadap file kelas atau jar yang ada. Anda dapat menilai upaya transisi tanpa harus melakukan kompilasi ulang.

jdeprscan mencari penggunaan API yang tidak digunakan lagi atau dihapus. Penggunaan API yang tidak digunakan lagi bukanlah masalah pemblokiran, tetapi merupakan sesuatu yang perlu dilihat. Apakah ada file jar yang diperbarui? Apakah Anda perlu mencatat masalah untuk mengatasi penggunaan API yang tidak digunakan lagi? Penggunaan API yang dihapus adalah masalah pemblokiran yang harus ditangani sebelum Anda mencoba menjalankan di Java 11.

jdeps, yang merupakan penganalisis dependensi kelas Java. Saat digunakan dengan --jdk-internals opsi, jdeps memberi tahu Anda kelas mana yang bergantung pada API internal mana. Anda dapat terus menggunakan API internal di Java 11, tetapi mengganti penggunaan harus menjadi prioritas. Halaman wiki OpenJDK Alat Analisis Dependensi Java telah merekomendasikan penggantian untuk beberapa API internal JDK yang umum digunakan.

Ada plugin jdeps dan jdeprscan untuk Gradle dan Maven. Kami merekomendasikan menambahkan alat ini ke lingkungan pengembangan Anda.

Kompilator Java itu sendiri, javac, adalah alat lain di kotak alat Anda. Peringatan dan kesalahan yang Anda dapatkan dari jdeprscan dan jdeps akan keluar dari kompilator. Keuntungan menggunakan jdeprscan dan jdeps adalah Anda dapat menjalankan alat-alat ini melalui jar dan file kelas yang ada, termasuk pustaka pihak ketiga.

Apa yang tidak dapat dilakukan jdeprscan dan jdeps adalah memperingatkan tentang penggunaan refleksi untuk mengakses API yang dienkapsulasi. Akses reflektif diperiksa saat runtime. Pada akhirnya, Anda harus menjalankan kode di Java 11 untuk mengetahui dengan pasti.

Menggunakan jdeprscan

Cara termudah untuk menggunakan jdeprscan adalah dengan memberikan file jar dari build yang ada. Anda juga dapat memberinya direktori, seperti direktori output pengkompilasi, atau nama kelas individual. Gunakan --release 11 opsi untuk mendapatkan daftar API yang paling lengkap yang tidak digunakan lagi. Jika Anda ingin memprioritaskan API mana yang tidak digunakan lagi, putar kembali pengaturan ke --release 8. API yang tidak digunakan lagi di Java 8 kemungkinan akan dihapus lebih cepat dari API yang tidak digunakan lagi baru-baru ini.

jdeprscan --release 11 my-application.jar

Alat jdeprscan menghasilkan pesan kesalahan jika mengalami masalah dalam menyelesaikan kelas dependen. Contohnya:error: cannot find class org/apache/logging/log4j/Logger Menambahkan kelas dependen ke --class-path atau menggunakan jalur kelas aplikasi disarankan, tetapi alat akan melanjutkan pemindaian tanpanya. Argumennya adalah --class-path. Tidak ada variasi lain dari argumen class-path yang akan berfungsi.

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

Output ini memberi tahu kita bahwa com.company.Util kelas memanggil konstruktor yang tidak digunakan lagi dari java.lang.Double kelas. Javadoc akan merekomendasikan API untuk digunakan sebagai ganti API yang tidak digunakan lagi. Tidak ada jumlah pekerjaan yang akan diselesaikan error: cannot find class sun/misc/BASE64Encoder karena ini adalah API yang telah dihapus. Karena Java 8, java.util.Base64 harus digunakan.

Jalankan jdeprscan --release 11 --list untuk memahami API apa yang tidak digunakan lagi sejak Java 8. Untuk mendapatkan daftar API yang telah dihapus, jalankan jdeprscan --release 11 --list --for-removal.

Menggunakan jdeps

Gunakan jdeps, dengan --jdk-internals opsi untuk menemukan dependensi pada API internal JDK. Opsi baris perintah --multi-release 11 diperlukan untuk contoh ini karena log4j-core-2.13.0.jar adalah file jar multi-rilis. Tanpa opsi ini, jdeps akan mengeluh jika menemukan file jar multi-rilis. Opsi menentukan versi file kelas mana yang akan diperiksa.

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   

Output memberikan beberapa saran yang baik tentang menghilangkan penggunaan API internal JDK! Jika memungkinkan, API pengganti disarankan. Nama modul tempat paket dienkapsulasi diberikan dalam tanda kurung. Nama modul dapat digunakan dengan --add-exports atau --add-opens jika perlu untuk secara eksplisit memutus enkapsulasi.

Penggunaan sun.misc.BASE64Encoder atau sun.misc.BASE64Decoder akan menghasilkan java.lang.NoClassDefFoundError dalam Java 11. Kode yang menggunakan API ini harus dimodifikasi untuk menggunakan java.util.Base64.

Cobalah untuk menghilangkan penggunaan API apa pun yang berasal dari modul jdk.unsupported. API dari modul ini akan mereferensikan JDK Enhancement Proposal (JEP) 260 sebagai pengganti yang disarankan. Singkatnya, JEP 260 mengatakan bahwa penggunaan API internal akan didukung sampai API pengganti tersedia. Meskipun kode Anda dapat menggunakan API internal JDK, kode tersebut akan terus berjalan, setidaknya untuk sementara waktu. Lihat JEP 260 karena menunjuk ke penggantian untuk beberapa API internal. handel variabel dapat digunakan sebagai pengganti beberapa sun.misc.Unsafe API, misalnya.

jdeps dapat melakukan lebih dari sekadar memindai penggunaan internal JDK. Ini adalah alat yang berguna untuk menganalisis dependensi dan untuk menghasilkan file info modul. Lihat dokumentasi untuk informasi selengkapnya.

Menggunakan javac

Mengkompilasi dengan JDK 11 akan memerlukan pembaruan untuk membuat skrip, alat, kerangka kerja pengujian, dan pustaka yang disertakan. Gunakan -Xlint:unchecked opsi untuk javac untuk mendapatkan detail tentang penggunaan API internal JDK dan peringatan lainnya. Mungkin juga perlu menggunakan --add-opens atau --add-reads untuk mengekspos paket yang dienkapsulasi ke kompilator (lihat JEP 261).

Pustaka dapat mempertimbangkan pengemasan sebagai file jar multi-rilis. File jar multi-rilis memungkinkan Anda mendukung runtime Java 8 dan Java 11 dari file jar yang sama. Mereka menambahkan kompleksitas ke build. Cara membangun jar multi-rilis berada di luar cakupan dokumen ini.

Berjalan di Java 11

Sebagian besar aplikasi harus berjalan pada Java 11 tanpa modifikasi. Hal pertama yang harus dicoba adalah menjalankan pada Java 11 tanpa mengkompilasi ulang kode. Inti dari hanya menjalankan adalah untuk melihat peringatan dan kesalahan apa yang keluar dari eksekusi. Pendekatan ini mendapatkan
aplikasi untuk berjalan pada Java 11 lebih cepat dengan berfokus pada minimum yang perlu dilakukan.

Sebagian besar masalah yang mungkin Anda temui dapat diselesaikan tanpa harus mengkompilasi ulang kode. Jika masalah harus diperbaiki dalam kode, buat perbaikan tetapi terus kompilasi dengan JDK 8. Jika memungkinkan, bekerjalah untuk menjalankan aplikasi dengan java versi 11 sebelum mengkompilasi dengan JDK 11.

Periksa opsi baris perintah

Sebelum berjalan di Java 11, lakukan pemindaian cepat opsi baris perintah. Opsi yang telah dihapus akan menyebabkan Java Virtual Machine (JVM) keluar. Pemeriksaan ini sangat penting jika Anda menggunakan opsi pengelogan GC karena telah berubah secara drastis dari Java 8. Alat JaCoLine adalah alat yang baik untuk digunakan untuk mendeteksi masalah dengan opsi baris perintah.

Periksa pustaka pihak ketiga

Sumber masalah potensial adalah pustaka pihak ketiga yang tidak Anda kontrol. Anda dapat secara proaktif memperbarui pustaka pihak ketiga ke versi yang lebih baru. Atau Anda dapat melihat apa yang hilang dari menjalankan aplikasi dan hanya memperbarui pustaka yang diperlukan. Masalah dengan memperbarui semua pustaka ke versi terbaru adalah membuatnya lebih sulit untuk menemukan akar penyebab jika ada beberapa kesalahan dalam aplikasi. Apakah kesalahan terjadi karena beberapa pustaka yang diperbarui? Atau apakah kesalahan disebabkan oleh beberapa perubahan runtime? Masalah dengan memperbarui hanya yang diperlukan adalah mungkin perlu beberapa iterasi untuk diselesaikan.

Rekomendasi di sini adalah membuat perubahan sesedikit mungkin dan memperbarui pustaka pihak ketiga sebagai upaya terpisah. Jika Anda memperbarui pustaka pihak ketiga, lebih sering daripada tidak Anda menginginkan versi terbaru dan terhebat yang kompatibel dengan Java 11. Bergantung pada seberapa jauh di belakang versi Anda saat ini, Anda mungkin ingin mengambil pendekatan yang lebih hati-hati dan meningkatkan ke versi pertama yang kompatibel dengan Java 9+.

Selain melihat catatan rilis, Anda dapat menggunakan jdeps dan jdeprscan untuk menilai file jar. Selain itu, OpenJDK Quality Group mempertahankan halaman wiki Quality Outreach yang mencantumkan status pengujian banyak proyek Free Open Source Software (FOSS) terhadap versi OpenJDK.

Mengatur pengumpulan sampah secara eksplisit

Parallel garbage collector (Parallel GC) adalah GC default di Java 8. Jika aplikasi menggunakan default, maka GC harus diatur secara eksplisit dengan opsi baris perintah -XX:+UseParallelGC. Default berubah di Java 9 menjadi Garbage First garbage collector (G1GC). Untuk membuat perbandingan yang adil dari aplikasi yang berjalan pada Java 8 versus Java 11, pengaturan GC harus sama. Bereksperimen dengan pengaturan GC harus ditangguhkan sampai aplikasi telah divalidasi pada Java 11.

Mengatur opsi default secara eksplisit

Jika berjalan pada VM HotSpot, mengatur opsi baris perintah -XX:+PrintCommandLineFlags akan membuang nilai opsi yang diatur oleh VM, terutama default yang ditetapkan oleh GC. Jalankan dengan bendera ini pada Java 8 dan gunakan opsi cetak saat berjalan di Java 11. Sebagian besar, defaultnya sama dari 8 hingga 11. Tetapi menggunakan pengaturan dari 8 memastikan paritas.

Mengatur opsi baris perintah --illegal-access=warn disarankan. Di Java 11, menggunakan refleksi untuk mengakses API internal JDK akan menghasilkan peringatan akses reflektif ilegal. Secara default, peringatan hanya dikeluarkan untuk akses ilegal pertama. Pengaturan --illegal-access=warn akan menyebabkan peringatan pada setiap akses reflektif ilegal. Anda akan menemukan lebih banyak kasus jika akses ilegal dengan opsi diatur untuk memperingatkan. Tetapi Anda juga akan mendapatkan banyak peringatan redundan.
Setelah aplikasi berjalan pada Java 11, atur --illegal-access=deny untuk meniru perilaku runtime Java di masa mendatang. Dimulai dengan Java 16, defaultnya adalah --illegal-access=deny.

Kewaspadaan ClassLoader

Di Java 8, Anda dapat mentransmisikan loader kelas sistem ke URLClassLoader. Ini biasanya dilakukan oleh aplikasi dan pustaka yang ingin menyuntikkan kelas ke classpath saat runtime. Hierarki pemuat kelas telah berubah di Java 11. Loader kelas sistem (juga dikenal sebagai loader kelas aplikasi) sekarang menjadi kelas internal. Casting ke URLClassLoader akan melemparkan ClassCastException pada runtime. Java 11 tidak memiliki API untuk secara dinamis menambah classpath pada runtime tetapi dapat dilakukan melalui refleksi, dengan peringatan yang jelas tentang menggunakan API internal.

Di Java 11, pemuat kelas boot hanya memuat modul inti. Jika Anda membuat pemuat kelas dengan induk null, itu mungkin tidak menemukan semua kelas platform. Di Java 11, Anda perlu meneruskan ClassLoader.getPlatformClassLoader() alih-alih null sebagai loader kelas induk dalam kasus seperti itu.

Perubahan data lokal

Sumber default untuk data lokal di Java 11 diubah dengan JEP 252 menjadi Repositori Data Lokal Umum Unicode Consortium. Ini mungkin berdampak pada pemformatan yang dilokalkan. Atur properti sistem java.locale.providers=COMPAT,SPI untuk kembali ke perilaku lokal Java 8, jika perlu.

Potensi Masalah

Berikut adalah beberapa masalah umum yang mungkin Anda temui. Ikuti tautan untuk detail selengkapnya tentang masalah ini.

Opsi yang tidak dikenal

Jika opsi baris perintah telah dihapus, aplikasi akan mencetak Unrecognized option: atau Unrecognized VM option diikuti dengan nama opsi yang menyinggung. Opsi yang tidak dikenali akan menyebabkan VM keluar. Opsi yang tidak digunakan lagi, tetapi tidak dihapus, akan menghasilkan peringatan VM.

Secara umum, opsi yang dihapus tidak memiliki penggantian dan satu-satunya jalan lain adalah menghapus opsi dari baris perintah. Pengecualian adalah opsi untuk pengelogan pengumpulan sampah. Pengelogan GC diisi ulang di Java 9 untuk menggunakan kerangka kerja pengelogan JVM terpadu. Lihat "Tabel 2-2 Pemetaan Bendera Pengelogan Pengumpulan Sampah Warisan ke Konfigurasi Xlog" di bagian Aktifkan Pengelogan dengan Kerangka Kerja Pengelogan Terpadu JVM dari Referensi Alat Java SE 11.

Peringatan VM

Penggunaan opsi yang tidak digunakan lagi akan menghasilkan peringatan. Opsi tidak digunakan lagi ketika telah diganti atau tidak lagi berguna. Seperti halnya opsi yang dihapus, opsi ini harus dihapus dari baris perintah. Peringatan VM Warning: Option <option> was deprecated berarti bahwa opsi masih didukung, tetapi dukungan tersebut dapat dihapus di masa mendatang. Opsi yang tidak lagi didukung dan akan menghasilkan peringatan VM Warning: Ignoring option. Opsi yang tidak lagi didukung tidak berpengaruh pada runtime.

Halaman web VM Options Explorer menyediakan daftar lengkap opsi yang telah ditambahkan atau dihapus dari Java sejak JDK 7.

Kesalahan: Tidak dapat membuat Mesin Virtual Java

Pesan kesalahan ini dicetak ketika JVM menemukan opsi yang tidak dikenali.

PERINGATAN: Operasi akses reflektif ilegal telah terjadi

Ketika kode Java menggunakan refleksi untuk mengakses API internal JDK, runtime akan mengeluarkan peringatan akses reflektif ilegal.

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

Artinya, modul belum mengekspor paket yang sedang diakses melalui refleksi. Paket ini dienkapsulasi dalam modul dan, pada dasarnya, API internal. Peringatan dapat diabaikan sebagai upaya pertama untuk memulai dan menjalankan di Java 11. Runtime Java 11 memungkinkan akses reflektif sehingga kode warisan dapat terus berfungsi.

Untuk mengatasi peringatan ini, cari kode yang diperbarui yang tidak menggunakan API internal. Jika masalah tidak dapat diselesaikan dengan kode yang diperbarui, --add-exports atau --add-opens opsi baris perintah dapat digunakan untuk membuka akses ke paket. Opsi ini memungkinkan akses ke jenis yang tidak didukung dari satu modul dari modul lain.

--add-exports Opsi ini memungkinkan modul target untuk mengakses jenis publik dari paket bernama modul sumber. Terkadang kode akan digunakan setAccessible(true) untuk mengakses anggota non-publik dan API. Ini dikenal sebagai refleksi mendalam. Dalam hal ini, gunakan --add-opens untuk memberikan akses kode Anda ke anggota paket non-publik. Jika Anda tidak yakin apakah akan menggunakan --add-exports atau --add-opens, mulailah dengan --add-exports.

Opsi --add-exports atau --add-opens harus dipertimbangkan sebagai solusi, bukan solusi jangka panjang. Menggunakan opsi ini memutus enkapkulasi sistem modul, yang dimaksudkan untuk menjaga API internal JDK tidak digunakan. Jika API internal dihapus atau berubah, aplikasi akan gagal. Akses reflektif akan ditolak di Java 16, kecuali jika akses diaktifkan oleh opsi baris perintah seperti --add-opens. Untuk meniadakan perilaku di masa mendatang, atur --illegal-access=deny pada baris perintah.

Peringatan dalam contoh di atas dikeluarkan karena sun.nio.ch paket tidak diekspor oleh java.base modul. Dengan kata lain, tidak ada exports sun.nio.ch; dalam module-info.java file modul java.base. Ini dapat diselesaikan dengan --add-exports=java.base/sun.nio.ch=ALL-UNNAMED. Kelas yang tidak didefinisikan dalam modul secara implisit milik modul yang tanpa nama, secara harfiah bernama ALL-UNNAMED.

java.lang.reflect.InaccessibleObjectException

Pengecualian ini menunjukkan bahwa Anda mencoba memanggil setAccessible(true) pada bidang atau metode kelas yang dienkapsulasi. Anda mungkin juga mendapatkan peringatan akses reflektif ilegal. Gunakan --add-opens untuk memberikan akses kode Anda ke anggota paket non-publik. Pesan pengecualian akan memberi tahu Anda modul "tidak membuka" paket ke modul yang mencoba memanggil setAccessible. Jika modul adalah "modul tanpa nama", gunakan UNNAMED-MODULE sebagai modul target dalam opsi --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

NoClassDefFoundError kemungkinan besar disebabkan oleh paket terpisah, atau dengan mereferensikan modul yang dihapus.

NoClassDefFoundError disebabkan oleh paket terpisah

Paket terpisah adalah ketika paket ditemukan di lebih dari satu pustaka. Gejala masalah paket terpisah adalah bahwa kelas yang Anda ketahui berada di jalur kelas tidak ditemukan.

Masalah ini hanya akan terjadi saat menggunakan jalur modul. Sistem modul Java mengoptimalkan pencarian kelas dengan membatasi paket ke satu modul bernama. Runtime memberikan preferensi ke jalur modul di atas jalur kelas saat melakukan pencarian kelas. Jika paket dibagi antara modul dan jalur kelas, hanya modul yang digunakan untuk melakukan pencarian kelas. Ini dapat menyebabkan NoClassDefFound kesalahan.

Cara mudah untuk memeriksa paket terpisah adalah dengan menyambungkan jalur modul dan jalur kelas Anda ke jdeps dan menggunakan jalur ke file kelas aplikasi Anda sebagai <jalur>. Jika ada paket terpisah, jdeps akan mencetak peringatan: Warning: split package: <package-name> <module-path> <split-path>.

Masalah ini dapat diatasi dengan menggunakan --patch-module <module-name>=<path>[,<path>] untuk menambahkan paket terpisah ke dalam modul bernama.

NoClassDefFoundError disebabkan oleh penggunaan modul Java EE atau CORBA

Jika aplikasi berjalan pada Java 8 tetapi melempar java.lang.NoClassDefFoundError atau java.lang.ClassNotFoundException, kemungkinan aplikasi menggunakan paket dari modul Java EE atau CORBA. Modul ini tidak digunakan lagi di Java 9 dan dihapus di Java 11.

Untuk mengatasi masalah ini, tambahkan dependensi runtime ke proyek Anda.

Modul yang dihapus Paket yang Terpengaruh Dependensi yang disarankan
Java API untuk XML Web Services (JAX-WS) java.xml.ws JAX WS RI Runtime
Arsitektur Java untuk XML Binding (JAXB) java.xml.bind JAXB Runtime
Kerangka Kerja Aktivasi JavaBeans (JAV) java.activation Kerangka Kerja Aktivasi JavaBeans (TM)
Anotasi Umum java.xml.ws.annotation Javax Annotation API
Arsitektur Broker Permintaan Objek Umum (CORBA) java.corba GlassFish CORBA ORB
API Transaksi Java (JTA) java.transaction API Transaksi Java

-Xbootclasspath/p bukan lagi opsi yang didukung

Dukungan untuk -Xbootclasspath/p telah dihapus. Gunakan --patch-module sebagai gantinya. Opsi --patch-module dijelaskan dalam JEP 261. Cari bagian berlabel "Patching konten modul". --patch-module dapat digunakan dengan javac dan dengan java untuk mengganti atau menambah kelas dalam modul.

Apa yang dilakukan --patch-module, pada dasarnya, adalah memasukkan modul patch ke dalam pencarian kelas sistem modul. Sistem modul akan mengambil kelas dari modul patch terlebih dahulu. Ini adalah efek yang sama dengan pra-pending bootclasspath di Java 8.

UnsupportedClassVersionError

Pengecualian ini berarti Anda mencoba menjalankan kode yang dikompilasi dengan versi Java yang lebih baru pada versi Java yang lebih lama. Misalnya, Anda berjalan di Java 11 dengan jar yang dikompilasi dengan JDK 13.

Versi Java Versi format file kelas
8 52
9 53
10 54
11 55
12 56
13 57

Langkah berikutnya

Setelah aplikasi berjalan pada Java 11, pertimbangkan untuk memindahkan pustaka dari jalur kelas dan ke jalur modul. Cari versi pustaka yang diperbarui yang bergantung pada aplikasi Anda. Pilih pustaka modular, jika tersedia. Gunakan jalur modul sebanyak mungkin, bahkan jika Anda tidak berencana menggunakan modul di aplikasi Anda. Menggunakan jalur modul memiliki performa yang lebih baik untuk pemuatan kelas daripada jalur kelas.