Objek yang tidak dapat diubah adalah objek di mana bidang internal (atau setidaknya, semua bidang internal yang memengaruhi perilaku eksternalnya) tidak dapat diubah.
Ada banyak keuntungan dari string yang tidak dapat diubah:
Kinerja: Lakukan operasi berikut:
String substring = fullstring.substring(x,y);
C yang mendasarinya untuk metode substring () mungkin kira-kira seperti ini:
// Assume string is stored like this:
struct String { char* characters; unsigned int length; };
// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
struct String* out = malloc(sizeof(struct String));
out->characters = in->characters + begin;
out->length = end - begin;
return out;
}
Perhatikan bahwa tidak ada karakter yang harus disalin! Jika objek String dapat diubah (karakter dapat berubah nanti) maka Anda harus menyalin semua karakter, jika tidak, perubahan karakter dalam substring akan tercermin dalam string lain nanti.
Konkurensi: Jika struktur internal objek yang tidak dapat diubah valid, itu akan selalu valid. Tidak ada kemungkinan bahwa utas berbeda dapat membuat keadaan tidak valid dalam objek itu. Oleh karena itu, objek yang tidak berubah adalah Thread Safe .
Pengumpulan sampah: Jauh lebih mudah bagi pemulung untuk membuat keputusan logis tentang benda-benda yang tidak dapat diubah.
Namun, ada juga kerugian untuk ketidakberubahan:
Kinerja: Tunggu, saya pikir Anda mengatakan kinerja terbalik dari kekekalan! Ya, terkadang, tapi tidak selalu. Ambil kode berikut:
foo = foo.substring(0,4) + "a" + foo.substring(5); // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder
Kedua baris tersebut menggantikan karakter keempat dengan huruf "a". Tidak hanya potongan kode kedua yang lebih mudah dibaca, tetapi juga lebih cepat. Lihatlah bagaimana Anda harus melakukan kode yang mendasari untuk foo. Substring mudah, tetapi sekarang karena sudah ada karakter di ruang lima dan sesuatu yang lain mungkin merujuk foo, Anda tidak bisa begitu saja mengubahnya; Anda harus menyalin seluruh string (tentu saja beberapa fungsi ini diabstraksi menjadi fungsi dalam C yang mendasarinya, tetapi intinya di sini adalah untuk menunjukkan kode yang dieksekusi semua di satu tempat).
struct String* concatenate(struct String* first, struct String* second)
{
struct String* new = malloc(sizeof(struct String));
new->length = first->length + second->length;
new->characters = malloc(new->length);
int i;
for(i = 0; i < first->length; i++)
new->characters[i] = first->characters[i];
for(; i - first->length < second->length; i++)
new->characters[i] = second->characters[i - first->length];
return new;
}
// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));
Perhatikan bahwa concatenate dipanggil dua kali yang berarti bahwa seluruh string harus diulang! Bandingkan ini dengan kode C untuk bar
operasi:
bar->characters[4] = 'a';
Operasi string yang bisa berubah jelas jauh lebih cepat.
Kesimpulan: Dalam kebanyakan kasus, Anda ingin string yang tidak dapat diubah. Tetapi jika Anda perlu melakukan banyak menambahkan dan memasukkan ke dalam string, Anda membutuhkan kemampuan untuk berubah-ubah. Jika Anda ingin manfaat keamanan konkurensi dan pengumpulan sampah bersamanya kuncinya adalah menjaga objek Anda yang bisa berubah-ubah tetap lokal ke suatu metode:
// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
StringBuilder mutable;
boolean first = true;
for(int i = 0; i < strings.length; i++)
{
if(!first) first = false;
else mutable.append(separator);
mutable.append(strings[i]);
}
return mutable.toString();
}
Karena mutable
objek adalah referensi lokal, Anda tidak perlu khawatir tentang keamanan konkurensi (hanya satu utas yang pernah menyentuhnya). Dan karena itu tidak direferensikan di tempat lain, itu hanya dialokasikan pada stack, jadi itu dialokasikan segera setelah panggilan fungsi selesai (Anda tidak perlu khawatir tentang pengumpulan sampah). Dan Anda mendapatkan semua manfaat kinerja dari mutabilitas dan imutabilitas.