Setiap class kini hidup rapi di dalam package, tetapi konsekuensinya muncul segera: class dari package lain tidak lagi bisa dipanggil dengan nama sederhananya. Java menyediakan tiga cara untuk merujuk class lintas package — single-type import, on-demand import, dan fully qualified name — dan ketiganya punya tempat masing-masing dalam kode sehari-hari. Pada Chapter ini kita akan membahas cara kerja ketiganya, batasan on-demand import yang sering mengejutkan pemula, serta cara keluar dari konflik nama ketika dua package menyediakan class bernama sama.
Cara Import Bekerja #
Pernyataan import tidak menyalin kode apa pun ke berkas kita — import hanyalah instruksi untuk compiler javac agar nama sederhana dipetakan ke nama lengkap tertentu saat resolusi nama. Ketika compiler membaca List, import java.util.List membuat compiler menerjemahkannya menjadi java.util.List di bytecode hasil kompilasi. Dengan demikian, import murni urusan waktu kompilasi dan tidak memengaruhi ukuran maupun kecepatan program saat berjalan.
Satu pengecualian membuat hidup kita mudah: isi package java.lang (String, Integer, System, Math, dan kawan-kawannya) diimpor secara otomatis ke setiap berkas sumber. Itulah sebabnya kita bisa menulis System.out.println sejak program pertama tanpa satu baris import. Seluruh package lain — termasuk java.util dan java.io — harus diimpor secara eksplisit.
Single-Type Import #
Bentuk paling lazim menyebut satu class secara utuh: import java.util.ArrayList;. Satu berkas boleh memuat banyak single-type import, dan kebiasaan umum di komunitas Java adalah mengimpornya satu per satu, bukan memakai tanda bintang. Contoh berikut memakai dua single-type import untuk membangun daftar belanja:
import java.util.ArrayList;
import java.util.List;
public class DaftarBelanja {
public static void main(String[] args) {
List<String> belanja = new ArrayList<>();
belanja.add("Beras 5 kg");
belanja.add("Minyak goreng 1 L");
belanja.add("Gula 1 kg");
System.out.println("Daftar belanja Budi:");
for (int i = 0; i < belanja.size(); i++) {
System.out.println((i + 1) + ". " + belanja.get(i));
}
}
}Output yang Dihasilkan:
Daftar belanja Budi:
1. Beras 5 kg
2. Minyak goreng 1 L
3. Gula 1 kgMari kita telaah baris-baris kuncinya:
- Baris 1-2 (
import java.util.ArrayList;danimport java.util.List;): dua single-type import — namaListdipetakan kejava.util.List, danArrayListkejava.util.ArrayList. Compiler menolak dua single-type import yang memetakan nama sederhana sama. - Baris 6 (
List<String> belanja = new ArrayList<>();): tipeListpada sisi kiri danArrayListpada sisi kanan dikenali berkat pemetaan import; tanpa import, baris ini harus ditulisjava.util.List<String> belanja = new java.util.ArrayList<>();. - Baris 12 (
belanja.get(i)): methodgetmilik interfaceListmengembalikan elemen sesuai indeks — polaimportmemudahkan kode tetap fokus pada logika, bukan pada nama panjang.
On-Demand Import dan Batasannya #
Bentuk kedua mengimpor seluruh class dalam satu package sekaligus dengan tanda bintang: import java.util.*;.Compiler kemudian mencari nama sederhana yang belum terdefinisi di berkas tersebut di seluruh class package java.util. Bentuk ini memangkas baris import, tetapi ada satu batasan yang wajib dipahami: on-demand import tidak mengikutsertakan subpackage. Package java.util.function adalah package tersendiri, bukan bagian dari java.util, sehingga class Predicate tidak ikut terimpor. Contoh berikut sengaja memuat kesalahan itu:
import java.util.*;
public class ImporMassal {
public static void main(String[] args) {
List<String> nama = new ArrayList<>();
nama.add("Budi");
Predicate<String> panjang = s -> s.length() > 2;
System.out.println(nama + " -> " + panjang.test("Siti"));
}
}Kompilasi berkas tersebut gagal dengan pesan yang kita verifikasi sendiri:
ImporMassal.java:8: error: cannot find symbol
Predicate<String> panjang = s -> s.length() > 2;
^
symbol: class Predicate
location: class ImporMassalNama List dan ArrayList lolos karena memang anggota java.util, sedangkan Predicate tidak ditemukan — kita perlu satu baris tambahan import java.util.function.Predicate;. Inilah alasan utama banyak tim melarang on-demand import: pembaca kode tidak bisa melihat dari package mana sebuah class berasal hanya dengan membaca daftar import.
Nama Memenuhi dan Konflik Nama #
Ketika dua package menyediakan class dengan nama sederhana sama, single-type import hanya boleh memilih salah satu. Kasus klasiknya adalah java.util.Date versus java.sql.Date — keduanya bernama Date tetapi digunakan untuk keperluan berbeda. Solusinya: impor salah satunya, dan rujuk yang lain dengan fully qualified name alias nama memenuhi yang dituliskan langsung di tempat pemakaian:
import java.time.LocalDate;
import java.util.Date;
public class KonflikTanggal {
public static void main(String[] args) {
LocalDate lahir = LocalDate.of(2001, 5, 17);
Date tanggalUtil = Date.from(
lahir.atStartOfDay(java.time.ZoneId.of("Asia/Jakarta")).toInstant());
java.sql.Date tanggalSql = java.sql.Date.valueOf(lahir);
System.out.println("java.util.Date : " + tanggalUtil);
System.out.println("java.sql.Date : " + tanggalSql);
}
}Output yang Dihasilkan:
java.util.Date : Thu May 17 00:00:00 WIB 2001
java.sql.Date : 2001-05-17Mari kita bedah baris-baris pentingnya:
- Baris 2 (
import java.util.Date;): nama sederhanaDatekini resmi merujukjava.util.Datedi seluruh berkas ini. - Baris 11 (
java.sql.Date tanggalSql = java.sql.Date.valueOf(lahir);): classDatekedua dipakai dengan nama lengkapnya secara langsung — penulisan nama memenuhi tidak memerlukan import dan selalu sah di posisi mana pun. - Dua baris
System.out.println: hasil cetak memperlihatkan perbedaan representasi —java.util.Datemencetak momen waktu lengkap dengan zona, sedangkanjava.sql.Date(turunanjava.util.Dateuntuk kolom tanggal SQL) hanya mencetak bagian tanggalnya.
Nama memenuhi juga berguna untuk pemakaian sekali pakai tanpa menambah baris import, misalnya java.util.concurrent.TimeUnit.SECONDS.sleep(500) di satu titik kode.
Import untuk Member Static #
Selain class dan interface, import juga bisa menyasar member static — method dan konstanta. Bentuknya import static java.lang.Math.sqrt; (single) atau import static java.lang.Math.*; (on-demand) sehingga sqrt(2) bisa ditulis tanpa awalan Math.. Karena topik ini berkaitan erat dengan member static dan keterbacaan kode, kita bahas tuntas pada Chapter Static Import.
Aturan Penulisan yang Rapi #
Konvensi penulisan import yang dipegang luas: letakkan seluruh import setelah deklarasi package, urutkan berdasarkan package dengan import static di kelompok terpisah, dan hapus import yang tidak terpakai — IDE modern melakukannya otomatis. Compiler hanya menolak import yang bentrok nama sederhananya, bukan import yang tidak terpakai; kode yang bersih tetap tanggung jawab kita.
Kita sudah bisa memanggil class lintas package dengan tiga gaya. Namun nama package sendiri tidak boleh asal pilih — ada konvensi domain terbalik yang dipakai seluruh ekosistem Java, dan itulah topik Chapter berikutnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
DaftarBelanja.java
Unduh berkasimport java.util.ArrayList;
import java.util.List;
public class DaftarBelanja {
public static void main(String[] args) {
List<String> belanja = new ArrayList<>();
belanja.add("Beras 5 kg");
belanja.add("Minyak goreng 1 L");
belanja.add("Gula 1 kg");
System.out.println("Daftar belanja Budi:");
for (int i = 0; i < belanja.size(); i++) {
System.out.println((i + 1) + ". " + belanja.get(i));
}
}
}
ImporMassal.java
Unduh berkasimport java.util.*;
public class ImporMassal {
public static void main(String[] args) {
List<String> nama = new ArrayList<>();
nama.add("Budi");
Predicate<String> panjang = s -> s.length() > 2;
System.out.println(nama + " -> " + panjang.test("Siti"));
}
}
KonflikTanggal.java
Unduh berkasimport java.time.LocalDate;
import java.util.Date;
public class KonflikTanggal {
public static void main(String[] args) {
LocalDate lahir = LocalDate.of(2001, 5, 17);
Date tanggalUtil = Date.from(
lahir.atStartOfDay(java.time.ZoneId.of("Asia/Jakarta")).toInstant());
java.sql.Date tanggalSql = java.sql.Date.valueOf(lahir);
System.out.println("java.util.Date : " + tanggalUtil);
System.out.println("java.sql.Date : " + tanggalSql);
}
}