Mengenal tiga fitur Java modern yang mereduksi boilerplate: enum dengan field dan method plus switch pattern matching, record sebagai data carrier immutable otomatis, dan sealed class/interface untuk hierarki tertutup yang aman terhadap lupa kasus.

Sejauh ini kita bekerja dengan class klasik: banyak baris untuk sesuatu yang sebenarnya sederhana. Episode ini memperkenalkan tiga fitur Java modern yang membuat OOP jauh lebih ekspresif: enum untuk kumpulan nilai terbatas, record untuk data immutable, dan sealed class untuk hierarki tertutup.
Mengapa ketiganya revolusioner? Karena mereka mengubah bahasa dari verbose menjadi expressive — mengekspresikan maksud kode secara langsung, bukan lewat pola yang harus diingat. Java 21+ menyatukan ketiganya dengan pattern matching sehingga kode menjadi lebih pendek, lebih jelas, dan lebih aman.
enum merepresentasikan kumpulan konstanta yang terbatas dan dikenal — status pesanan, tipe kartu, level akses:
public enum Status {
MENUNGGU,
DIPROSES,
SELESAI,
DIBATALKAN
}Status status = Status.SELESAI;Sebelum enum ada (Java 5), orang menulis konstanta public static final int STATUS_SELESAI = 2 — yang rawan salah nilai dan tidak type-safe. Enum menyelesaikan keduanya: nilai salah akan ditolak compiler.
Enum bukan sekadar label — ia bisa membawa state dan perilaku:
public enum TipeKartu {
DEBIT(1.0),
KREDIT(2.5),
PREMIUM(0.5);
private final double biayaPersen;
TipeKartu(double biayaPersen) {
this.biayaPersen = biayaPersen;
}
public double hitungBiaya(double nominal) {
return nominal * biayaPersen / 100;
}
}Pemakaian: TipeKartu.KREDIT.hitungBiaya(100000). Setiap konstanta enum adalah object — dengan state (biayaPersen) dan behavior (hitungBiaya). Ini OOP dalam bentuk terkecil.
Sejak JDK 21, switch atas enum (dan tipe lain) bisa menggunakan pattern matching dengan ekspresi:
public String label(Status status) {
return switch (status) {
case MENUNGGU -> "Menunggu pembayaran";
case DIPROSES -> "Sedang dikemas";
case SELESAI -> "Telah terkirim";
case DIBATALKAN -> "Dibatalkan";
};
}Perhatikan: switch sebagai ekspresi (mengembalikan nilai), panah -> tanpa break, dan jika enum bersifat sealed/enum, compiler memastikan semua kasus tercakup. Detail ini akan terasa saat kita menggabungkan dengan sealed class di bawah.
Class yang hanya membawa data membutuhkan banyak boilerplate: constructor, getter, equals, hashCode, toString — semuanya formulaik dan rawan error (terutama equals). Record menghilangkan semuanya:
public record Alamat(String jalan, String kota, String kodePos) {}Satu baris menghasilkan: constructor penuh, getter (jalan(), kota(), kodePos()), equals(), hashCode(), dan toString() — semuanya otomatis. Semua komponen private final — record immutable sejak lahir.
public class Main {
public static void main(String[] args) {
Alamat a1 = new Alamat("Jl. Merdeka", "Jakarta", "10110");
Alamat a2 = new Alamat("Jl. Merdeka", "Jakarta", "10110");
System.out.println(a1); // Alamat[jalan=Jl. Merdeka, kota=Jakarta, kodePos=10110]
System.out.println(a1.equals(a2)); // true
System.out.println(a1.kota()); // Jakarta
}
}equals otomatis membandingkan semua komponen — masalah yang menyakitkan jika ditulis manual. Record juga mendukung compact constructor (dari episode 5) untuk validasi.
| Pola lama | Pengganti record |
|---|---|
| Class data + getter + equals + hashCode + toString | Record (satu baris) |
| JavaBeans yang diisi setter bertahap | Record dengan constructor penuh |
| DTO yang disalin antar lapisan | Record immutable |
Karena immutable dan auto-equals, record menjadi pilihan default untuk DTO (data transfer object) — persis yang dipakai framework modern dan Optional di episode 13.
sealed membatasi siapa yang boleh menjadi subclass. Ini "closed hierarchy" untuk kasus yang memang seharusnya tertutup:
public sealed class Bentuk permits Lingkaran, Persegi, Segitiga {}public final class Lingkaran extends Bentuk {
double jariJari;
}
public final class Persegi extends Bentuk {
double sisi;
}
public final class Segitiga extends Bentuk {
double alas, tinggi;
}Setiap subclass yang di-permits wajib salah satu dari: final, sealed, atau non-sealed. Class lain yang mencoba extends Bentuk akan error compile.
Keuntungan sebenarnya muncul saat dipadukan dengan switch pattern matching. Karena compiler tahu persis subclass apa saja yang ada, ia bisa memastikan semua kasus ditangani:
public double luas(Bentuk bentuk) {
return switch (bentuk) {
case Lingkaran l -> Math.PI * l.jariJari * l.jariJari;
case Persegi p -> p.sisi * p.sisi;
case Segitiga s -> 0.5 * s.alas * s.tinggi;
};
}Jika besok ada subclass baru Trapesium ditambahkan ke permits, compiler langsung memaksa kalian menambah case di sini — tidak mungkin lupa. Ini momen "dengan pattern matching, compiler jadi rekan" yang akan kita pakai lagi di episode 13 dan 19.
Sealed cocok ketika domain matematis/terbatas: bentuk geometri, AST (abstract syntax tree) bahasa, jenis message dalam protokol. Sealed tidak cocok untuk domain yang tumbuh cepat dan terbuka — di sana interface biasa (open hierarchy) lebih fleksibel.
Warning
Jangan langsung membungkus seluruh model dengan sealed. Sealed adalah keputusan desain yang disengaja: ia menukar fleksibilitas (tidak ada subclass baru tanpa edit) dengan keamanan (compiler menjamin kelengkapan). Gunakan saat hierarki memang kecil dan stabil.
public enum JenisNotifikasi { EMAIL, SMS, PUSH }
public sealed interface Notifikasi permits EmailNotif, SmsNotif, PushNotif {
String format();
}
public record EmailNotif(String alamat, String isi) implements Notifikasi {
public String format() {
return "EMAIL ke " + alamat + ": " + isi;
}
}
public record SmsNotif(String nomor, String isi) implements Notifikasi {
public String format() {
return "SMS ke " + nomor + ": " + isi;
}
}
public record PushNotif(String perangkat, String isi) implements Notifikasi {
public String format() {
return "PUSH ke " + perangkat + ": " + isi;
}
}Tiga fitur saling melengkapi: enum untuk kategori, record untuk data immutable per jenis, sealed untuk hierarki yang pasti. Pemakai tinggal memanggil format() secara polymorphic (episode 8) tanpa cabang.
Tip
Rule of thumb Java modern: record untuk data, enum untuk kumpulan terbatas, sealed untuk hierarki tertutup. Jika class kalian "hanya bawa data", itu record. Jika hanya kumpulan konstanta, itu enum. Jika subclass jumlahnya sudah jelas di kepala, pertimbangkan sealed.
Inti yang harus dibawa pulang:
Di episode 11 selanjutnya kita akan membahas generics & collections — type parameter, bounded wildcards, type erasure, lalu List, Set, dan Map dari Java Collections Framework. Sampai jumpa di episode 11!