Interoperabilitas Java

Memanggil pustaka Java, koleksi Java, dan konverter di antara dua ekosistem.

Daftar isi

Karena kode Scala dikompilasi menjadi bytecode yang sama dengan kode Java, seluruh pustaka Java dapat digunakan dari Scala tanpa lapisan penghubung apa pun. Topik ini membahas cara memanggil kelas dan pustaka Java langsung dari Scala, cara scala-cli mengompilasi proyek campuran yang berisi berkas .java dan .scala sekaligus, serta konversi koleksi di antara dua ekosistem dengan scala.jdk.CollectionConverters. Perbedaan konvensi panggilan yang perlu dijaga agar kedua sisi tetap kompatibel dibahas pada bagian akhir.

Pustaka Java digunakan langsung dari Scala#

Kelas Java diperlakukan sebagai kelas biasa di Scala. Kelas dari pustaka standar Java seperti java.time.LocalDate atau java.util.ArrayList cukup diimpor dengan import, lalu dibuat dengan new dan metodenya dipanggil seperti pada kelas Scala. Pustaka Java pihak ketiga yang beredar sebagai berkas .jar juga berlaku sama, karena tidak ada perbedaan format bytecode di antara keduanya.

Beberapa konvensi panggilan Java diterjemahkan secara alami. Metode statis (static method) diakses melalui nama kelasnya, sebagaimana KonversiSuhu.fahrenheitKeCelsius(98.6) pada bagian berikutnya. Metode Java selalu dipanggil dengan tanda kurung meskipun tidak memiliki parameter, karena tidak ada aturan Scala yang membolehkan metode Java ditulis tanpa tanda kurung. Nilai kembalian void milik Java dilihat oleh Scala sebagai Unit, sehingga metode yang tidak menghasilkan apa pun tetap dapat dipanggil dari ekspresi Scala.

Proyek campuran dengan scala-cli#

scala-cli dapat mengompilasi berkas .java dan .scala yang berada dalam satu direktori sebagai satu proyek. Caranya adalah memberikan masukan berupa direktori, bukan satu berkas, sehingga kelas Java ikut dikompilasi bersama kode Scala. Karena proyek campuran berikut memuat dua titik masuk, yaitu main milik kelas Java dan @main milik Scala, direktif //> using mainClass interop pada berkas Scala menetapkan program mana yang dijalankan.

java KonversiSuhu.java
// Kelas Java sederhana untuk konversi satuan suhu
public class KonversiSuhu {

    // Mengonversi suhu dari Fahrenheit ke Celsius
    public static double fahrenheitKeCelsius(double fahrenheit) {
        return (fahrenheit - 32.0) * 5.0 / 9.0;
    }

    // Program kecil agar berkas ini dapat dijalankan sendiri
    public static void main(String[] args) {
        System.out.printf("98.6 Fahrenheit = %.1f Celsius%n", fahrenheitKeCelsius(98.6));
    }
}
text Keluaran
98.6 Fahrenheit = 37.0 Celsius

Kelas Java di atas dapat diuji sendiri dengan perintah java KonversiSuhu.java, sedangkan metode statisnya dipanggil dari sisi Scala pada program campuran berikut.

scala interoperabilitas.scala
//> using mainClass interop
// Proyek campuran: memanggil kelas Java dan mengonversi koleksi
import scala.jdk.CollectionConverters.*

import java.time.LocalDate
import java.util.ArrayList

@main def interop(): Unit =
  // Kelas Java KonversiSuhu dipanggil langsung dari Scala
  val celsius = KonversiSuhu.fahrenheitKeCelsius(98.6)
  println(f"98.6 Fahrenheit setara $celsius%.1f Celsius")

  // Pustaka Java bawaan dipakai tanpa pembungkus
  val tanggal = LocalDate.of(2026, 1, 15)
  println(s"Tanggal uji: $tanggal")

  // ArrayList Java diisi lalu dilihat dari sisi Scala
  val peserta = new ArrayList[String]()
  peserta.add("ali")
  peserta.add("budi")
  val daftarScala = peserta.asScala.toList
  println(s"Hasil asScala.toList: $daftarScala")
  println(s"Elemen pertama via get: ${peserta.get(0)}")
  println(s"Elemen pertama via apply: ${daftarScala(0)}")

  // List Scala dikembalikan ke sisi Java
  val daftarJava = daftarScala.asJava
  println(s"Hasil asJava: $daftarJava")
bash
# mengompilasi dan menjalankan seluruh proyek campuran
scala-cli run .
text Keluaran
98.6 Fahrenheit setara 37.0 Celsius
Tanggal uji: 2026-01-15
Hasil asScala.toList: List(ali, budi)
Elemen pertama via get: ali
Elemen pertama via apply: ali
Hasil asJava: [ali, budi]

Baris pertama keluaran berasal sepenuhnya dari kelas Java, yaitu hasil KonversiSuhu.fahrenheitKeCelsius(98.6) yang dicetak sebagai 37.0 dengan format satu angka desimal. Baris kedua menggunakan LocalDate dari pustaka java.time tanpa pembungkus apa pun. Baris-baris sisanya melibatkan koleksi, dan polanya dibahas pada bagian berikut.

Koleksi Java dan konverter#

Koleksi Java seperti ArrayList bersifat mutable, sedangkan koleksi Scala yang lazim bersifat immutable, sehingga keduanya tidak dapat dipertukarkan secara langsung. Jembatannya adalah objek scala.jdk.CollectionConverters yang menyediakan metode perluasan (extension method) asScala dan asJava. Pada ArrayList yang berisi string, peserta.asScala menghasilkan Buffer yang merupakan tampilan (view) di atas koleksi Java aslinya, dan toList menyalinnya menjadi List Scala yang berdiri sendiri.

Sifat tampilan dan salinan ini perlu diperhatikan karena keduanya terlihat sama ketika dicetak.

Pada program di atas, daftarScala = peserta.asScala.toList menghasilkan List(ali, budi) yang sepenuhnya milik sisi Scala. Sebaliknya, daftarScala.asJava membungkus List Scala menjadi objek yang memenuhi antarmuka java.util.List, sehingga metode Java seperti get dapat dipanggil padanya. Ketika dicetak, koleksi Java menampilkan format kurung siku [ali, budi], sedangkan koleksi Scala menampilkan format List(ali, budi), dan perbedaan ini berguna untuk mengenali sisi asal sebuah koleksi.

Perbedaan konvensi antara Java dan Scala#

Di luar koleksi, beberapa perbedaan konvensi muncul secara berulang saat kedua bahasa dipertemukan. Tabel berikut merangkum pasangan yang paling sering ditemui.

AspekSisi JavaSisi Scala
Akses elemen menurut indekspeserta.get(0)daftarScala(0) melalui apply
Nilai yang tidak adanullOption dengan None
Metode tanpa nilai kembalianvoidUnit
Akses atribut melalui getterdata.getNilai()properti data.nilai pada kelas Scala

get dan apply sama-sama mengambil elemen pada indeks tertentu, tetapi get adalah metode khas antarmuka java.util.List, sedangkan apply adalah metode penerapan (application method) yang membuat penulisan daftarScala(0) mungkin. Pada program di atas, kedua cara menghasilkan ali dari data yang sama. Perbedaan penanganan null lebih berisiko, karena kelas Java dapat mengembalikan null tanpa aba-aba.

Konvensi void dan Unit tidak menuntut penyesuaian apa pun karena penerjemahannya otomatis. Perbedaan getter hanya berlaku searah, yaitu atribut kelas Scala dapat diakses seperti properti, sedangkan atribut kelas Java tetap dipanggil dengan getter-nya.

Ringkasan#

  • Kelas dan pustaka Java dipanggil dari Scala tanpa lapisan penghubung, dengan metode Java selalu ditulis bertanda kurung dan metode statis diakses melalui nama kelasnya.
  • scala-cli mengompilasi proyek campuran .java dan .scala dalam satu direktori ketika masukannya berupa direktori, yaitu scala-cli run ..
  • asScala dan asJava menghasilkan tampilan yang terhubung ke koleksi asal, sedangkan toList menyalin isi ke koleksi immutable yang berdiri sendiri.
  • Konvensi yang perlu dijaga mencakup get versus apply, penanganan null dengan Option, serta pemetaan void ke Unit yang berlangsung otomatis.

Referensi#