Menggeser aplikasi dari Java 8 atau 11 ke Java 25 bukan loncatan buta: sejak 1996 kompatibilitas menjadi janji resmi platform, dan jutaan baris kode lawas tetap berjalan di JVM modern tanpa recompile. Meski begitu, “hampir selalu kompatibel” tidak sama dengan “selalu”: API usang dihapus bertahap, perilaku bawaan bisa disesuaikan, dan kode yang menyalahgunakan bagian internal JDK bisa patah di versi baru. Chapter penutup ini merangkum model kompatibilitas Java, jadwal dukungan LTS untuk merencanakan upgrade, cara menyasar versi lama dari JDK baru, serta alat bantu yang memindai API usang sebelum menjadi masalah.
Tiga Jenis Kompatibilitas #
Dokumen migrasi resmi Oracle membedakan tiga lapis janji. Kompatibilitas biner adalah yang terkuat: class file hasil kompilasi versi lama tetap berjalan di JVM baru — JVM membaca class file lama, bukan sebaliknya. Kompatibilitas sumber menjamin kode sumber lawas tetap terkompilasi oleh javac baru; tipenya lebih lemah — kata kunci baru bisa bentrok dengan identifier lama, seperti enum yang mematahkan kode lawas saat masuk Java 5, alasan kata kunci modern seperti record dan sealed sengaja dibuat kontekstual. Kompatibilitas perilaku adalah yang paling longgar: hasil eksekusi bisa disesuaikan untuk membenahi cacat — contohnya String yang sejak Java 9 menyimpan byte alih-alih char, menghemat memori tanpa mengubah semantik. Upgrade yang tertib memeriksa ketiganya, bukan hanya yang pertama.
Tonggak LTS dan Jadwal Dukungan #
| Versi LTS | Rilis | Dukungan diperpanjang (Oracle) |
|---|---|---|
| Java 8 | Maret 2014 | Desember 2030 |
| Java 11 | September 2018 | Januari 2032 |
| Java 17 | September 2021 | September 2029 |
| Java 21 | September 2023 | September 2031 |
| Java 25 | September 2025 | September 2033 |
LTS berikutnya direncanakan September 2027 (Java 29). Pola yang sehat untuk aplikasi berumur panjang: menetap di LTS, lalu berpindah ke LTS berikutnya jauh sebelum dukungan yang lama berakhir — jarak dua tahun antar LTS cukup untuk satu siklus upgrade yang tenang.
Menulis Kode yang Sadar Versi #
Runtime menyediakan Runtime.Version untuk mengambil versi secara pasti, dan reflection dapat mendeteksi API yang sudah berubah nasib. Contoh teruji berikut memeriksa tonggak versi serta status tiga API legendaris:
public class CekMigrasi {
// Deteksi API lama lewat reflection: ada, dihapus, atau dinonaktifkan?
static boolean methodAda(Class<?> kelas, String nama) {
try {
kelas.getMethod(nama);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
public static void main(String[] args) {
var versi = Runtime.version();
System.out.println("runtime : Java " + versi.feature()
+ " build " + versi.build().orElse(-1));
int[] tonggak = {8, 11, 17, 21, 25};
for (int v : tonggak) {
String status = versi.feature() >= v ? "sudah terlewati" : "belum tercapai";
System.out.printf("tonggak %2d : %s%n", v, status);
}
System.out.println("Thread.suspend : "
+ (methodAda(Thread.class, "suspend") ? "ada" : "sudah dihapus"));
System.out.println("Thread.stop : "
+ (methodAda(Thread.class, "stop") ? "ada, kini selalu error" : "sudah dihapus"));
// SecurityManager dinonaktifkan permanen sejak Java 24 (JEP 486).
try {
System.setSecurityManager(null);
} catch (UnsupportedOperationException e) {
System.out.println("SecurityManager : dinonaktifkan permanen");
}
}
}Output yang Dihasilkan:
runtime : Java 25 build 1
tonggak 8 : sudah terlewati
tonggak 11 : sudah terlewati
tonggak 17 : sudah terlewati
tonggak 21 : sudah terlewati
tonggak 25 : sudah terlewati
Thread.suspend : sudah dihapus
Thread.stop : ada, kini selalu error
SecurityManager : dinonaktifkan permanenBedah baris-per-baris untuk bagian pentingnya:
- Baris
Runtime.version().feature(): mengembalikan nomor rilis fitur (25), komponen paling berguna untuk pemeriksaan programatik;build()berupaOptionalIntyang dicetak sebagai angka build JDK. - Method
methodAda(Class, String): mencari method publik lewat reflection —Thread.suspendtidak ditemukan (dihapus dari JDK modern), sementaraThread.stopmasih tercantum tetapi selalu melemparUnsupportedOperationExceptionsaat dipanggil; javadoc JDK 25 menyebutnya secara eksplisit “UnsupportedOperationException - always”. - Blok
System.setSecurityManager(null): sejak Java 24 (JEP 486), Security Manager dinonaktifkan permanen; pemanggilannya melemparUnsupportedOperationException— aplikasi lawas yang memasang Security Manager harus dirombak pada bagian itu.
Menyasar Versi Lama dari JDK Baru #
Compiler modern dapat menghasilkan class file untuk JVM lama lewat flag --release, sekaligus memeriksa kode terhadap API yang benar dari versi target:
javac --release 17 Aplikasi.java| Versi target | Class file (major) | Catatan |
|---|---|---|
| Java 8 | 52 | Masih umum di bank dan instansi |
| Java 11 | 55 | Titik lompatan umum dari 8 |
| Java 17 | 61 | Basis banyak framework modern |
| Java 21 | 65 | LTS sebelumnya |
| Java 25 | 69 | Target Course ini |
Memindai API Usang Sebelum Upgrade #
Dua alat bawaan JDK memindai aplikasi tanpa menjalankannya. jdeprscan mencari pemakaian API deprecated — khususnya yang ditandai for removal:
jdeprscan --release 25 --for-removal aplikasi.jar
jdeps --jdk-internals aplikasi.jarjdeps --jdk-internals melengkapi dengan menemukan pemakaian internal JDK (sun.misc.*, dan kawan-kawan) yang tidak dijamin stabil antar versi — kategori yang paling sering mematahkan aplikasi lama. Hasil keduanya menjadi daftar kerja pra-upgrade yang konkret: per-API, per-class.
Setelah seluruh fitur modern terpetakan dan jalur upgrade jelas, Section ini tertutup. Aplikasi Java kini dapat ditulis dengan record, switch expression, virtual thread, dan pola-pola modern lainnya — lalu dipelihara lintas versi dengan rencana, bukan dengan harapan.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
CekMigrasi.java
Unduh berkaspublic class CekMigrasi {
// Deteksi API lama lewat reflection: ada, dihapus, atau dinonaktifkan?
static boolean methodAda(Class<?> kelas, String nama) {
try {
kelas.getMethod(nama);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
public static void main(String[] args) {
var versi = Runtime.version();
System.out.println("runtime : Java " + versi.feature()
+ " build " + versi.build().orElse(-1));
int[] tonggak = {8, 11, 17, 21, 25};
for (int v : tonggak) {
String status = versi.feature() >= v ? "sudah terlewati" : "belum tercapai";
System.out.printf("tonggak %2d : %s%n", v, status);
}
System.out.println("Thread.suspend : "
+ (methodAda(Thread.class, "suspend") ? "ada" : "sudah dihapus"));
System.out.println("Thread.stop : "
+ (methodAda(Thread.class, "stop") ? "ada, kini selalu error" : "sudah dihapus"));
// SecurityManager dinonaktifkan permanen sejak Java 24 (JEP 486).
try {
System.setSecurityManager(null);
} catch (UnsupportedOperationException e) {
System.out.println("SecurityManager : dinonaktifkan permanen");
}
}
}