Method Reference

Meringkas lambda menjadi method reference dalam empat jenisnya.

Daftar isi

Method reference adalah penulisan lambda yang diringkas menjadi rujukan ke metode yang sudah ada, ditandai simbol :: di antara nama pemiliknya dan nama metodenya. Topik ini mengenalkan empat jenis method reference, mengujinya dalam satu program yang dapat dijalankan, lalu menilai kapan bentuk ini lebih mudah dibaca daripada lambda biasa. Setiap contoh juga dituliskan lambda padanannya agar keterkaitan keduanya tetap terlihat.

Empat jenis method reference#

Meskipun simbolnya sama, :: memuat empat makna yang berbeda menurut pemilik metodenya, dan perbedaan itu penting karena kompiler menyusun perilaku lambda padanan secara berbeda untuk tiap jenis. Tabel berikut merangkum keempatnya beserta contoh dan lambda yang setara.

JenisBentukContohLambda padanannya
Metode staticNamaKelas::metodeStaticInteger::parseInts -> Integer.parseInt(s)
Metode milik objek tertentunamaObjek::metodeSystem.out::printlns -> System.out.println(s)
Metode milik objek sembarang dari suatu tipeNamaKelas::metodeString::lengths -> s.length()
KonstruktorNamaKelas::newArrayList::new() -> new ArrayList<>()

Jenis ketiga sering menjadi sumber kebingungan karena bentuk tulisannya sama persis dengan jenis pertama, yaitu NamaKelas::metode. Bedanya terletak pada peran parameter pertama lambda padanannya. Pada String::length, parameter pertama menjadi objek yang dipanggil metodenya, sehingga padanannya adalah s -> s.length(), bukan pemanggilan metode static milik String. Kompiler menentukan maknanya dari tipe target, yaitu interface fungsional yang bentuk parameternya menuntut penerima semacam itu.

Jenis konstruktor memakai nama kelas diikuti new, dan sifatnya mengikuti interface fungsional yang menampungnya. Supplier<List<String>> menuntut tanpa parameter, sehingga ArrayList::new berarti menyediakan daftar kosong baru, sedangkan Function<String, Produk> pada kelas dengan konstruktor satu parameter akan memanggil new Produk(s). Satu rujukan yang sama pun dapat berarti banyak perilaku, tergantung kontrak yang menerima.

Menguji keempat jenis dalam satu program#

Program berikut menjalankan keempat jenis di atas satu daftar kata yang sama. Perubahan pada tiap kata dilakukan lewat stream, yakni aliran data yang dibangun dari List lalu dioper melalui rangkaian operasi seperti map, dan aliran inilah bahasan utama modul ini.

java EmpatJenisReference.java
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class EmpatJenisReference {

    static String beriKapital(String teks) {
        return teks.toUpperCase();
    }

    public static void main(String[] args) {
        List<String> kata = List.of("ombak", "api", "rumah");

        // 1. metode static: NamaKelas::namaMetode
        List<String> kapital = kata.stream()
                .map(EmpatJenisReference::beriKapital)
                .toList();
        System.out.println("Metode static     : " + kapital);

        // 2. metode milik objek tertentu: namaObjek::namaMetode
        String pembuka = "JADWAL:";
        List<String> berlabel = kata.stream()
                .map(pembuka::concat)
                .toList();
        System.out.println("Objek tertentu    : " + berlabel);

        // 3. metode milik objek sembarang dari suatu tipe: NamaKelas::namaMetode
        List<Integer> panjang = kata.stream()
                .map(String::length)
                .toList();
        System.out.println("Objek sembarang   : " + panjang);

        // 4. konstruktor: NamaKelas::new
        Supplier<List<String>> pembuatDaftar = ArrayList::new;
        List<String> daftar = pembuatDaftar.get();
        daftar.add("kursor");
        System.out.println("Konstruktor       : " + daftar);

        // bentuk klasik lain: System.out::println sebagai Consumer
        kata.forEach(System.out::println);
    }
}
text Keluaran
Metode static     : [OMBAK, API, RUMAH]
Objek tertentu    : [JADWAL:ombak, JADWAL:api, JADWAL:rumah]
Objek sembarang   : [5, 3, 5]
Konstruktor       : [kursor]
ombak
api
rumah

Jenis pertama memakai metode static beriKapital milik kelas yang sama, dan rujukannya ditulis lengkap dengan nama kelasnya sebagai EmpatJenisReference::beriKapital. Jenis kedua menempel pada satu objek tertentu, yaitu string pembuka, sehingga tiap elemen dikirim sebagai argumen ke pembuka.concat(...) dan hasilnya menyatu dengan label itu. Jenis ketiga menyisakan tiap elemen sebagai penerima metode, sedangkan jenis keempat mengambil ArrayList::new sebagai Supplier yang menyediakan daftar kosong setiap kali dipanggil. Keempat rujukan itu menghasilkan keluaran berbeda dari sumber data yang sama persis.

java Contoh: method reference dan lambda padanannya
// tidak-dijalankan
map(k -> EmpatJenisReference.beriKapital(k)) // setara EmpatJenisReference::beriKapital
map(k -> pembuka.concat(k))                  // setara pembuka::concat
map(k -> k.length())                         // setara String::length

Aturan singkat dari keempat contoh di atas: method reference layak dipakai bila lambda hanya memindahkan satu argumen ke satu pemanggilan metode tanpa tambahan apa pun. Begitu ada gabungan teks, perhitungan tambahan, atau lebih dari satu pemanggilan, lambda biasa lebih jujur menyatakan maksudnya.

Kapan method reference lebih tepat#

Method reference paling efektif ketika namanya terbaca seperti kalimat. Bentuk map(String::length) terbaca sebagai “petakan setiap kata ke panjangnya”, dan forEach(System.out::println) terbaca sebagai “cetak setiap elemen”. Keterbacaan itu hilang bila rujukan memaksa pembaca membongkar isi metode untuk memahami maksudnya, misalnya ketika nama metodenya generik seperti proses atau handle tanpa konteks apa pun.

Ujian sederhananya adalah membaca keras-keras rujukan itu di dalam kalimat pipeline. Baris filter(this::lolosAmbang) terbaca “saring yang lolos ambang” dan langsung bermakna, sedangkan map(this::proses) memaksa pertanyaan lanjutan tentang isi proses itu. Karena itu method reference dan penamaan metode yang baik saling menopang, dan penilaian keterbacaannya selalu dilakukan pada konteks pipeline-nya, bukan pada berkas metode itu sendiri.

Bila isi lambda memanjang melebihi satu baris, perlakuan yang lebih baik adalah memindahkan logikanya ke metode bernama, lalu merujuknya dengan ::. Rujukan filter(this::lolosAmbang) lebih ringkas daripada lambda panjang sekaligus memberi nama pada kondisi tersebut, sehingga metode bernama itu dapat diuji secara terpisah. Cara ini menggabungkan keunggulan keduanya, yaitu keringanan lambda dan dokumentasi alami dari nama metode.

Kesalahan umum#

  • Menjodohkan method reference tanpa memperhatikan tipe target. String::length sah untuk Function<String, Integer> tetapi ditolak pada konteks yang bentuk parameternya berbeda. Periksa tipe targetnya terlebih dahulu sebelum meringkas lambda.
  • Mengira jenis ketiga adalah pemanggilan metode static. String::length memanggil metode milik tiap elemen, bukan metode static. Perhatikan parameter pertama pada lambda padanannya untuk membedakannya.
  • Memaksakan method reference pada logika berargumen tambahan. Bentuk k -> "nilai: " + k tidak dapat diringkas menjadi method reference karena ada teks lain yang digabungkan. Tulis lambda biasa atau pindahkan ke metode bernama.
  • Mengabaikan ambiguitas pada metode yang di-overload. Method reference yang menunjuk metode dengan banyak bentuk parameter dapat ambigu ketika tipe targetnya longgar. Persempit tipe target atau pakai lambda dengan parameter bertipe eksplisit.

Ringkasan#

  • Method reference meringkas lambda yang hanya memanggil satu metode menjadi bentuk :: dengan empat jenis, yaitu metode static, metode milik objek tertentu, metode milik objek sembarang dari suatu tipe, dan konstruktor.
  • Jenis pertama dan ketiga tertulis sama, sedangkan perbedaannya ada pada peran parameter pertama sebagai penerima metode.
  • Konstruktor dirujuk dengan NamaKelas::new dan maknanya mengikuti interface fungsional yang menampungnya, misalnya Supplier atau Function.
  • Method reference layak dipakai selama namanya tetap terbaca, dan lambda biasa lebih tepat bila logikanya membutuhkan argumen tambahan atau lebih dari satu pemanggilan.

Referensi#