Menyusun program dari fungsi-fungsi kecil baru bergaya fungsional ketika fungsi-fungsi itu bisa dirangkai — keluaran satu transformasi mengalir menjadi masukan transformasi berikutnya tanpa variabel perantara dan tanpa loop penjalin manual. Java menyediakan dua penggabung untuk itu: andThen dan compose. Keduanya menghasilkan Function baru dari dua Function lama; bedanya hanya pada urutan eksekusi — dan urutan itulah yang paling sering tertukar oleh programmer. Pada Chapter ini kita membangun pipeline teks berlapis, lalu membuktikan urutan kedua penggabung dengan jejak println yang bisa kita lihat langsung.
Pipeline dari Tahap-Tahap Kecil #
Tugasnya sederhana: hitung jumlah kata pada teks apa pun, dengan syarat teks dirapikan lebih dulu. Alih-alih menulis satu method besar int hitungKata(String teks) yang berisi trim(), toLowerCase(), split(), dan penghitungan sekaligus, kita pecah menjadi empat Function kecil lalu sambungkan dengan andThen:
import java.util.function.Function;
public class PipelineTeks {
public static void main(String[] args) {
// Empat tahap kecil, masing-masing satu tanggung jawab
Function<String, String> rapikan = String::trim;
Function<String, String> kecilkan = String::toLowerCase;
Function<String, String[]> pecah = teks -> teks.split(" ");
Function<String[], Integer> hitung = kata -> kata.length;
// Pipeline: keluaran setiap tahap mengalir ke tahap berikutnya
Function<String, Integer> jumlahKata = rapikan
.andThen(kecilkan)
.andThen(pecah)
.andThen(hitung);
String masukan = " Belajar Function Composition di Java ";
System.out.println("Jumlah kata : " + jumlahKata.apply(masukan));
System.out.println("Tahap rapikan saja : [" + rapikan.apply(masukan) + "]");
}
}Output yang Dihasilkan:
Jumlah kata : 5
Tahap rapikan saja : [Belajar Function Composition di Java]Mari kita bedah alur data pada program tersebut:
- Baris 6-9 (empat tahap): setiap tahap memegang satu tanggung jawab —
rapikanmembuang spasi tepi,kecilkanmenyeragamkan kapital,pecahmembelah menjadi array kata,hitungmenghitung panjang array. Tipe-tipe parameternya membentuk rantaiString → String → String → String[] → Integer. - Baris 12-16 (
rapikan.andThen(kecilkan).andThen(pecah).andThen(hitung)):andThenmenempel tahap berikutnya di sisi kanan; hasil penempelan adalahFunctionbaru, sehingga penempelan berikutnya bisa dilakukan lagi — pola berantai persis seperti memanggil method berurutan. VariabeljumlahKatabertipeFunction<String, Integer>: dari teks mentah langsung ke angka. - Baris 18-20:
jumlahKata.apply(masukan)mengalirkan" Belajar Function Composition di Java "melalui empat tahap dan menghasilkan5. Tahap mana pun bisa juga dipakai sendiri — baris 21 membuktikanrapikan.apply(masukan)tetap berguna tanpa pipeline. - Kenapa dipotong-potong? Setiap tahap bisa diuji terpisah, dipakai ulang di pipeline lain, dan diganti tanpa menyentuh tetangganya. Bila aturan berubah — misalnya pemisah menjadi koma — kita cukup mengganti tahap
pecah; tiga tahap lain tidak berubah.
compose vs andThen — Kontras yang Terbukti #
Kedua penggabung sama-sama menerima Function dan menghasilkan Function. Aturan urutannya:
f.andThen(g)— jalankanfdulu, lalug: hasil =g(f(x)). Mengingatkan kita membaca kiri-ke-kanan sesuai urutan penulisan.f.compose(g)— jalankangdulu, laluf: hasil =f(g(x)). Sesuai matematika:f∘gdibaca “f sesudah g”.
Program berikut memakai dua Function bernama f dan g yang masing-masing mencatat jejak saat dieksekusi, sehingga urutan pemanggilan tidak lagi perlu dipercaya — cukup dibaca:
import java.util.function.Function;
public class JejakUrutan {
public static void main(String[] args) {
Function<Integer, Integer> f = x -> {
System.out.println(" f dieksekusi pada " + x);
return x * 2;
};
Function<Integer, Integer> g = x -> {
System.out.println(" g dieksekusi pada " + x);
return x + 10;
};
System.out.println("f.compose(g).apply(5)");
System.out.println(" hasil = " + f.compose(g).apply(5));
System.out.println("f.andThen(g).apply(5)");
System.out.println(" hasil = " + f.andThen(g).apply(5));
}
}Output yang Dihasilkan:
f.compose(g).apply(5)
g dieksekusi pada 5
f dieksekusi pada 15
hasil = 30
f.andThen(g).apply(5)
f dieksekusi pada 5
g dieksekusi pada 10
hasil = 20Baca keluarannya perlahan — di sinilah letak bedanya:
- Bagian
compose(baris keluaran 1-3):g dieksekusi pada 5muncul lebih dulu.f.compose(g).apply(5)menjalankang(5)→15, menyerahkan15kepadaf, danf(15)menghasilkan30. Rumusnya:f.compose(g) = f(g(x))— argumencomposeselalu berjalan lebih dulu. - Bagian
andThen(baris keluaran 4-6): urutan terbalik.f dieksekusi pada 5lebih dulu:f(5)→10, lalug(10)→20. Rumusnya:f.andThen(g) = g(f(x))— pemilikandThenberjalan lebih dulu. - Angka yang berbeda (30 lawan 20) membuktikan kedua penggabung bukan dua nama untuk satu hal: dengan
fdangyang sama, hasil akhirnya berbeda karena urutan eksekusinya berbeda.
Kapan compose Lebih Alami #
andThen unggul saat kita membangun pipeline dari hulu ke hilir — tahap ditulis sesuai urutan kerjanya. compose unggul saat kita sudah punya fungsi inti dan ingin melapisi pembersihan di depannya: parseInt.compose(pembersih) terbaca “parse, dengan pembersihan disiapkan lebih dulu” — fungsi inti tetap menjadi subjek kalimatnya. Keduanya bisa dirangkai panjang; untuk rantai lebih dari empat tahap, pertimbangkan memecah menjadi beberapa variabel bernama seperti sebelumValidasi dan sesudahValidasi agar pembaca kode tidak kehilangan arah di tengah deretan andThen.
Dengan komposisi di tangan, behavior kita kini bisa tumbuh menjadi alur kerja yang panjang namun tetap tersusun dari potongan kecil. Ada satu batasan penting yang belum kita bahas: potongan-potongan itu menyimpan akses ke variabel di sekitarnya — closure. Java mengizinkannya dengan satu syarat ketat bernama effectively final, dan melanggar syarat itu berakhir di pesan error compiler. Chapter berikutnya membedah aturan tersebut sampai ke akarnya.
Referensi #
- Oracle: java.util.function.Function
- Oracle: java.util.function (Package Summary)
- dev.java: Lambda Expressions
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
JejakUrutan.java
Unduh berkasimport java.util.function.Function;
public class JejakUrutan {
public static void main(String[] args) {
Function<Integer, Integer> f = x -> {
System.out.println(" f dieksekusi pada " + x);
return x * 2;
};
Function<Integer, Integer> g = x -> {
System.out.println(" g dieksekusi pada " + x);
return x + 10;
};
System.out.println("f.compose(g).apply(5)");
System.out.println(" hasil = " + f.compose(g).apply(5));
System.out.println("f.andThen(g).apply(5)");
System.out.println(" hasil = " + f.andThen(g).apply(5));
}
}
PipelineTeks.java
Unduh berkasimport java.util.function.Function;
public class PipelineTeks {
public static void main(String[] args) {
// Empat tahap kecil, masing-masing satu tanggung jawab
Function<String, String> rapikan = String::trim;
Function<String, String> kecilkan = String::toLowerCase;
Function<String, String[]> pecah = teks -> teks.split(" ");
Function<String[], Integer> hitung = kata -> kata.length;
// Pipeline: keluaran setiap tahap mengalir ke tahap berikutnya
Function<String, Integer> jumlahKata = rapikan
.andThen(kecilkan)
.andThen(pecah)
.andThen(hitung);
String masukan = " Belajar Function Composition di Java ";
System.out.println("Jumlah kata : " + jumlahKata.apply(masukan));
System.out.println("Tahap rapikan saja : [" + rapikan.apply(masukan) + "]");
}
}