Tampilan
Kenapa penting
Hampir semua data yang masuk ke backend berbentuk teks: path URL, query string, header, body JSON, isi file CSV. Memvalidasi email, membersihkan input dari spasi, menyusun pesan log, atau membangun query SQL — semuanya pekerjaan String. Array adalah struktur data paling dasar di Java untuk menyimpan sekumpulan nilai; args di main, hasil split, sampai isi buffer jaringan semuanya array. Menguasai keduanya membuat bab-bab berikutnya (collections, stream, Spring) jauh lebih mudah dicerna.
Konsep inti
String itu immutable
String adalah tipe referensi (bab Tipe Data) yang tidak bisa diubah setelah dibuat. Semua method yang tampak "mengubah" — toLowerCase, strip, replace — sebenarnya mengembalikan objek String baru. Kalau hasilnya tidak disimpan ke variabel, perubahannya hilang.
java
public class StringBasics {
public static void main(String[] args) {
String email = " Budi.Santoso@Contoh.COM ";
String clean = email.strip().toLowerCase();
System.out.println(clean); // budi.santoso@contoh.com
System.out.println(clean.length()); // 23
System.out.println(clean.charAt(0)); // b
System.out.println(clean.indexOf('@')); // 12
System.out.println(clean.substring(0, 12)); // budi.santoso
System.out.println(clean.substring(13)); // contoh.com
System.out.println(clean.contains("@")); // true
System.out.println(clean.endsWith(".com")); // true
System.out.println(clean.replace('.', '_')); // budi_santoso@contoh_com
System.out.println(email); // tetap " Budi.Santoso@Contoh.COM "
}
}Beberapa hal yang perlu diingat dari contoh di atas:
| Method | Keterangan |
|---|---|
length() | jumlah karakter |
charAt(i) | karakter di indeks i (mulai dari 0), hasilnya bertipe char |
indexOf(x) | posisi pertama x, atau -1 bila tidak ada |
substring(a, b) | potongan dari indeks a sampai sebelum b; substring(a) sampai akhir |
contains, startsWith, endsWith | cek isi, hasilnya boolean |
toUpperCase(), toLowerCase() | ubah huruf besar/kecil |
strip() | buang spasi di awal & akhir (sadar Unicode; lebih disarankan daripada trim()) |
replace(a, b) | ganti semua a dengan b |
Method chaining seperti email.strip().toLowerCase() aman justru karena immutability: setiap langkah menghasilkan String baru yang langsung dipakai langkah berikutnya.
Cek kosong, memecah, dan menyusun teks
java
public class BlankCheck {
public static void main(String[] args) {
String spaces = " ";
System.out.println(spaces.isEmpty()); // false
System.out.println(spaces.isBlank()); // true
System.out.println("[" + spaces.strip() + "]"); // []
String csv = "java,spring,docker";
String[] tags = csv.split(",");
System.out.println(tags.length); // 3
System.out.println(String.join(" | ", tags)); // java | spring | docker
System.out.println("=".repeat(10)); // ==========
String line = "Pesanan %s berisi %d item".formatted("INV-001", 3);
System.out.println(line); // Pesanan INV-001 berisi 3 item
System.out.println(String.format("Total: Rp%d", 1250000)); // Total: Rp1250000
}
}isEmpty()hanyatrueuntuk"";isBlank()jugatrueuntuk teks berisi spasi saja — biasanya ini yang kamu mau saat memvalidasi input form.split(pemisah)memecah teks menjadi arrayString. Argumennya sebenarnya regular expression; untuk koma atau" +"(satu spasi atau lebih) kamu tidak perlu memikirkannya dulu.String.join(pemisah, array)kebalikan darisplit.formatted(...)danString.format(...)mengisi placeholder:%suntuk teks,%duntuk bilangan bulat,%.2funtuk desimal dua angka.
Membandingkan teks: equals, bukan ==
Di bab Operator & Ekspresi kamu sudah melihat sekilas bahwa == pada tipe referensi membandingkan alamat objek, bukan isinya. Untuk String ini sering menipu, karena kadang hasilnya kebetulan benar:
java
public class CompareStrings {
public static void main(String[] args) {
String a = "admin";
String b = "ad" + "min"; // digabung saat kompilasi → objek yang sama dengan a
String suffix = "min";
String c = "ad" + suffix; // digabung saat program berjalan → objek baru
System.out.println(a == b); // true (kebetulan objek yang sama)
System.out.println(a == c); // false (objek berbeda)
System.out.println(a.equals(c)); // true (isi sama)
System.out.println("ADMIN".equalsIgnoreCase(a)); // true
}
}Aturannya sederhana: selalu pakai equals (atau equalsIgnoreCase bila huruf besar/kecil tidak penting) untuk membandingkan isi teks.
StringBuilder untuk menyusun teks bertahap
Karena String immutable, hasil = hasil + x di dalam loop membuat objek baru di setiap iterasi. Untuk loop pendek tidak masalah, tapi untuk ratusan atau ribuan iterasi pakai StringBuilder — objek teks yang bisa diubah:
java
public class BuilderDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
if (i > 1) {
sb.append(", ");
}
sb.append("item-").append(i);
}
String result = sb.toString();
System.out.println(result); // item-1, item-2, item-3, item-4, item-5
System.out.println(new StringBuilder("halo").reverse()); // olah
}
}append mengembalikan builder yang sama, sehingga bisa dirantai. Panggil toString() di akhir untuk mendapatkan String.
Text block untuk teks multi-baris
Text block diapit tiga tanda kutip """ dan sangat praktis untuk SQL, JSON, atau template pesan. Indentasi yang sama di semua baris otomatis dibuang, dan kamu tidak perlu menulis \n atau meng-escape tanda kutip.
java
public class TextBlockDemo {
public static void main(String[] args) {
String sql = """
SELECT id, name, price
FROM products
WHERE price < ?
ORDER BY price
""";
System.out.print(sql);
String json = """
{
"id": %d,
"name": "%s"
}
""".formatted(42, "Kopi Gayo");
System.out.print(json);
}
}Output:
text
SELECT id, name, price
FROM products
WHERE price < ?
ORDER BY price
{
"id": 42,
"name": "Kopi Gayo"
}Text block yang ditutup """ di baris baru diakhiri karakter baris baru, karena itu contoh di atas memakai print, bukan println.
Array
Array menyimpan sejumlah nilai bertipe sama dengan ukuran tetap. Elemen diakses lewat indeks yang dimulai dari 0 sampai length - 1.
java
import java.util.Arrays;
public class ArrayBasics {
public static void main(String[] args) {
int[] scores = new int[3]; // {0, 0, 0}
scores[0] = 80;
scores[2] = 95;
System.out.println(Arrays.toString(scores)); // [80, 0, 95]
String[] roles = {"USER", "ADMIN", "EDITOR"};
System.out.println(roles.length); // 3
System.out.println(roles[roles.length - 1]); // EDITOR
for (String role : roles) {
System.out.println("- " + role);
}
int[] prices = {15000, 5000, 22000, 8000};
Arrays.sort(prices);
System.out.println(Arrays.toString(prices)); // [5000, 8000, 15000, 22000]
int[][] seats = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println(seats[1][2]); // 6
System.out.println(seats.length + " baris, " + seats[0].length + " kolom"); // 2 baris, 3 kolom
System.out.println(roles); // sesuatu seperti [Ljava.lang.String;@1b6d3586
}
}new int[3]membuat array berisi nilai default (0untuk angka,falseuntukboolean,nulluntuk referensi).{...}(array literal) membuat dan mengisi sekaligus.lengthadalah field, bukan method — tanpa tanda kurung (beda denganString.length()).- Enhanced for (
for (String role : roles)) cocok saat kamu hanya butuh nilainya, bukan indeksnya. Arrays.toStringdanArrays.sortberasal dari class utilitasjava.util.Arrays, karena itu perluimport. Mencetak array langsung hanya menampilkan tipe dan kode hash, bukan isinya.- Array dua dimensi adalah "array berisi array":
seats[1][2]artinya baris ke-2, kolom ke-3.
Array dan pass-by-value
Di bab Method kamu belajar Java selalu pass-by-value. Untuk array, nilai yang disalin adalah referensinya. Akibatnya method bisa mengubah isi array milik pemanggil, tapi tidak bisa mengganti array-nya:
java
import java.util.Arrays;
public class PassArray {
static void applyDiscount(int[] prices) {
for (int i = 0; i < prices.length; i++) {
prices[i] = prices[i] * 90 / 100; // mengubah isi array yang sama
}
}
static void replace(int[] prices) {
prices = new int[] {1, 1, 1}; // hanya mengganti salinan referensi
}
public static void main(String[] args) {
int[] prices = {10000, 20000};
applyDiscount(prices);
System.out.println(Arrays.toString(prices)); // [9000, 18000]
replace(prices);
System.out.println(Arrays.toString(prices)); // [9000, 18000]
}
}Varargs: jumlah argumen bebas
Kadang method perlu menerima argumen dalam jumlah bebas, seperti String.format("...", a, b, c). Caranya dengan varargs: tulis tipe... pada parameter terakhir. Di dalam method, parameter itu berupa array biasa.
java
public class VarargsDemo {
static int sum(int... numbers) { // numbers bertipe int[]
int total = 0;
for (int n : numbers) {
total += n;
}
return total;
}
static String logLine(String level, String... parts) {
return "[" + level + "] " + String.join(" ", parts);
}
public static void main(String[] args) {
System.out.println(sum()); // 0 — array kosong
System.out.println(sum(5)); // 5
System.out.println(sum(1, 2, 3)); // 6
System.out.println(sum(new int[] {4, 5})); // 9 — array biasa juga boleh
System.out.println(logLine("INFO", "order", "INV-001", "dibuat"));
}
}Aturannya: hanya boleh satu parameter varargs per method dan harus berada paling akhir. Kamu akan sering memakai method varargs milik library — String.format, formatted, dan nanti List.of(...) di M03 — jadi penting tahu bahwa di baliknya argumen itu dikumpulkan menjadi array.
args di main
Parameter String[] args di main berisi argumen yang kamu ketik setelah nama file saat menjalankan program:
java
public class Greet {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Pakai: java Greet.java <nama>");
return;
}
System.out.println("Halo, " + String.join(" ", args) + "!");
}
}bash
java Greet.java Budi Santoso # Halo, Budi Santoso!Contoh di dunia backend
Framework seperti Spring nanti mengurai query string dan menyusun JSON untukmu, tapi di baliknya terjadi operasi String dan array yang sama. Contoh kecil: mengambil parameter dari query string, menyamarkan email sebelum ditulis ke log, lalu menyusun baris log berformat JSON.
java
public class QueryParser {
static String valueOf(String query, String key) {
String[] pairs = query.split("&");
for (String pair : pairs) {
String[] parts = pair.split("=");
if (parts.length == 2 && parts[0].equals(key)) {
return parts[1];
}
}
return "";
}
static String maskEmail(String email) {
int at = email.indexOf('@');
if (at <= 1) {
return email;
}
return email.charAt(0) + "*".repeat(at - 1) + email.substring(at);
}
public static void main(String[] args) {
String query = "page=2&size=20&sort=price";
System.out.println(valueOf(query, "size")); // 20
System.out.println(valueOf(query, "filter")); // (kosong)
System.out.println(maskEmail("budi@contoh.com")); // b***@contoh.com
String log = """
{"event": "%s", "user": "%s"}""".formatted("LOGIN", maskEmail("sari@contoh.com"));
System.out.println(log); // {"event": "LOGIN", "user": "s***@contoh.com"}
}
}Menyamarkan data pribadi di log seperti maskEmail adalah praktik nyata di aplikasi production — log sering dibaca banyak orang dan disimpan lama.
Pertanyaan interview
1. Kenapa String dibuat immutable?
Object String bisa dibagi pakai bersama dengan aman (literal yang sama memakai object yang sama), aman dipakai banyak thread, dan nilai hash-nya bisa disimpan sehingga cepat dijadikan kunci HashMap. Dari sisi keamanan, nilai seperti path atau URL tidak bisa diubah diam-diam setelah divalidasi.
2. Apa beda String, StringBuilder, dan StringBuffer?
String immutable. StringBuilder bisa diubah dan cepat untuk menyusun teks bertahap, tetapi tidak aman dipakai beberapa thread sekaligus. StringBuffer adalah versi lama yang tersinkronisasi (aman antar-thread tapi lebih lambat) dan jarang dipakai di kode baru.
3. Apa beda array dan ArrayList?
Array berukuran tetap, bisa berisi primitif, dan panjangnya dibaca lewat field length. ArrayList berukuran dinamis, hanya berisi object (angka disimpan sebagai wrapper), dan punya banyak method bantu. Di kode bisnis kamu lebih sering memakai ArrayList/List — dibahas di M03.
Jebakan umum
- Membandingkan teks dengan
==. Kadang lolos saat dites dengan literal, lalu gagal saat teks datang dari input atau database. Selaluequals. - Lupa menyimpan hasil method
String.name.strip();tidak mengubahname; tulisname = name.strip();. - Indeks di luar batas. Indeks terakhir adalah
length - 1.arr[arr.length]atausubstringdengan indeks melebihi panjang teks menghentikan program denganArrayIndexOutOfBoundsException/StringIndexOutOfBoundsException(exception dibahas di M03). lengthvslength(). Array memakai fieldarr.length;Stringmemakai methodtext.length().- Mencetak array langsung.
System.out.println(arr)menampilkan[I@...; pakaiArrays.toString(arr). - Konkatenasi
+di loop besar. PakaiStringBuilder. - Menyusun SQL dengan menempelkan input user (
"... WHERE name = '" + input + "'") membuka celah SQL injection. Text block di atas memakai placeholder?yang nanti diisi secara aman oleh JDBC/JPA.
Ringkasan
Stringimmutable: method sepertistrip,toLowerCase,replacemengembalikan objek baru.- Bandingkan isi teks dengan
equals/equalsIgnoreCase, jangan==. isBlank,split,String.join,repeat, danformattedmenutup sebagian besar kebutuhan olah teks sehari-hari.StringBuilderuntuk menyusun teks bertahap di loop; text block"""untuk SQL/JSON multi-baris.- Array berukuran tetap, indeks
0sampailength - 1; gunakanjava.util.Arraysuntuk mencetak dan mengurutkan. - Mengoper array ke method menyalin referensinya — isinya bisa diubah oleh method tersebut; varargs (
tipe...) = array.