Menjelajahi Java 25 LTS dan fitur modern yang mengubah cara menulis OOP: structured concurrency dan string templates yang stabil, value objects dalam preview, flexible constructor bodies, serta rekap fitur JDK 21 seperti virtual threads dan pattern matching.

Selama 18 episode, kita memakai Java sebagai alat untuk belajar OOP. Episode ini memutar arah: kita melihat bagaimana Java itu sendiri berevolusi — dan bagaimana evolusinya memperkuat cara kita menulis kode. Java 25 LTS, dirilis 16 September 2025, adalah titik puncak dari transformasi Java modern yang dimulai sejak Java 8.
Mengapa penting memahami fitur bahasa terbaru? Karena kode yang memakai fitur modern lebih pendek, lebih aman, dan lebih jelas — dan kalian akan membacanya terus di kode orang lain. Ini bukan gimmick; ini bahasa yang sedang berkembang ke arah yang lebih ekspresif, dan kalian sudah memakai beberapa di antaranya (record, sealed, pattern matching).
Java sekarang merilis setiap 6 bulan. Dari rilis tersebut, hanya versi tertentu yang menjadi LTS (Long-Term Support) — didukung bertahun-tahun untuk produksi:
| Versi | Rilis | Sifat |
|---|---|---|
| JDK 8 | 2014 | LTS (masih dipakai legacy) |
| JDK 11 | 2018 | LTS |
| JDK 17 | 2021 | LTS |
| JDK 21 | Sep 2023 | LTS |
| JDK 25 | 16 Sep 2025 | LTS — fokus series ini |
| JDK 26 | 17 Mar 2026 | Feature release (support 6 bulan) |
Untuk produksi baru di 2026, rekomendasinya jelas: JDK 25 LTS. Verifikasi dengan java -version — series ini memakai Temurin 25.
Di episode 17 kita mencoba StructuredTaskScope. Di JDK 25, structured concurrency stabil — bukan lagi preview. Ini berarti API-nya final dan aman dipakai produksi tanpa flag.
Manfaat yang kini resmi:
ShutdownOnFailure).import java.util.concurrent.Future;
import java.util.concurrent.StructuredTaskScope;
public record Ringkasan(String pengguna, String katalog) {}
public class Layanan {
public Ringkasan buatRingkasan() throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> pengguna = scope.fork(this::ambilNamaPengguna);
Future<String> katalog = scope.fork(this::ambilKatalog);
scope.join();
scope.throwIfFailed();
return new Ringkasan(pengguna.resultNow(), katalog.resultNow());
}
}
}Dua subtask berjalan paralel; gagal satu, gagal semua; tidak ada thread bocor. Ini melengkapi virtual threads menjadi ekosistem concurrency yang utuh.
Interpolasi string telah lama menjadi fitur yang dirindukan dari bahasa lain. String templates menjadikannya bagian Java:
public class Main {
public static void main(String[] args) {
String nama = "Alya";
int saldo = 25000;
String pesan = STR."Halo \{nama}, saldo kamu \{saldo}";
System.out.println(pesan);
}
}Output: Halo Alya, saldo kamu 25000.
Perhatikan: STR adalah template processor, dan \{nama} adalah ekspresi yang diinterpolasi. Keunggulan dibanding concat string manual ("Halo " + nama + ", ..."):
Bandhingkan dengan String.format yang mudah salah urutan argumen. Untuk pesan, log, dan SQL dinamis, string templates adalah kemenangan besar keterbacaan.
Kita sudah mengenal record (episode 10) — object immutable sederhana. Value objects (JEP 401, preview di JDK 25) membawa konsep ini ke level berikutnya: object tanpa identity — dua value object dengan isi sama dianggap sama sepenuhnya, dan JVM bisa mengoptimalkannya.
public value class Uang {
private final long sen;
public Uang(long sen) {
this.sen = sen;
}
public long totalSen() {
return sen;
}
}Makna dari value class:
Uang(5000) dianggap sama.synchronized/wait/notify.Ini preview — jangan dipakai di produksi tanpa flag. Tapi arahnya jelas: Java menuju data-oriented programming di mana data yang ringan dan immutable menjadi citizen kelas satu. Ketika final (perkiraan JDK 26+), value objects akan mengubah cara kita merancang DTO dan model data.
Sebelum JDK 25, constructor harus memanggil super() di baris pertama — urutan inisialisasi kaku. Flexible constructor bodies (JEP 492) mengizinkan statement validasi sebelum super():
public class Pemesanan {
private final String id;
public Pemesanan(String id) {
if (id == null || id.isBlank()) {
throw new IllegalArgumentException("ID wajib diisi");
}
super(); // pemanggilan super kini boleh di akhir
this.id = id;
}
}Sebelumnya, validasi harus dilakukan setelah super() atau lewat pola-pola tidak langsung. Sekarang constructor bisa memvalidasi argumen sebelum memanggil superclass — hasilnya constructor yang lebih jujur dan lebih mudah dibaca. Perhatikan bahwa super() eksplisit kini diizinkan tidak di baris pertama (selama tidak di cabang percabangan yang bertentangan).
JNI (Java Native Interface) — mekanisme memanggil kode native C/C++ — di-deprecate di JDK 25. Bukan berarti Java anti-native: arahnya adalah FFM API (Foreign Function & Memory, JEP 454, stabil di JDK 22) yang lebih modern, aman, dan tanpa boilerplate JNI. Untuk 99% aplikasi, kalian tidak akan menyentuh native — tetapi memahami arah ini membantu saat membaca peta jalan Java.
Fitur JDK 21 yang sudah stabil dan kita pakai di series ini:
switch (episode 10) — exhaustive dan ekspresif.Yang ditambahkan JDK 25:
Tip
Fitur preview (value objects) bisa dicoba dengan flag --enable-preview. Namun untuk kode produksi: tetap di fitur stabil. Java sendiri memberi kompas yang jelas — fitur yang dipakai bertahun-tahun di produksi tanpa perubahan API itulah yang layak jadi pondasi.
Warning
Waspadai perbedaan versi: kode yang memakai fitur JDK 25 (string templates, structured concurrency) tidak bisa di-compile di JDK 21. Di tim produksi, pastikan semua orang memakai versi JDK yang sama — perbedaan satu rilis feature sering jadi sumber error compile yang membingungkan.
Inti yang harus dibawa pulang:
STR."... \{var} ..." yang type-safe.super().Di episode 20 selanjutnya kita akan membahas modern Java 26 & ekosistem — HTTP/3, AOT object caching, final semantics, perbaikan G1, lalu Maven/Gradle dan Spring Boot sebagai ekosistem produksi. Sampai jumpa di episode 20!