Konkurensi
Java didefinisikan dari awal dengan pertimbangan konkurensi. Seperti yang sering disebutkan, mutable yang dibagikan bermasalah. Satu hal dapat mengubah yang lain di belakang utas lainnya tanpa utas itu menyadarinya.
Ada sejumlah bug C ++ multithreaded yang telah muncul karena string yang dibagi - di mana satu modul berpikir aman untuk berubah ketika modul lain dalam kode telah menyimpan pointer ke sana dan berharap agar tetap sama.
'Solusi' untuk ini adalah bahwa setiap kelas membuat salinan defensif dari objek yang bisa berubah yang diteruskan ke sana. Untuk string yang dapat berubah, ini adalah O (n) untuk membuat salinan. Untuk string yang tidak dapat diubah, membuat salinan adalah O (1) karena itu bukan salinan, itu adalah objek yang sama yang tidak dapat diubah.
Dalam lingkungan multithreaded, objek yang tidak dapat diubah selalu dapat dibagi dengan aman antara satu sama lain. Ini mengarah pada pengurangan keseluruhan dalam penggunaan memori dan meningkatkan caching memori.
Keamanan
Banyak kali string diteruskan sebagai argumen untuk konstruktor - koneksi jaringan dan protocals adalah dua yang paling mudah terlintas dalam pikiran. Mampu mengubah ini pada waktu yang tidak ditentukan kemudian dalam eksekusi dapat menyebabkan masalah keamanan (fungsi berpikir itu terhubung ke satu mesin, tetapi dialihkan ke yang lain, tetapi segala sesuatu di objek terlihat seperti terhubung ke yang pertama ... bahkan string yang sama).
Java memungkinkan satu menggunakan refleksi - dan parameter untuk ini adalah string. Bahaya dari seseorang yang melewatkan string yang bisa dimodifikasi melalui jalan ke metode lain yang mencerminkan. Ini sangat buruk.
Kunci untuk Hash
Tabel hash adalah salah satu struktur data yang paling banyak digunakan. Kunci untuk struktur data sangat sering berupa string. Memiliki string yang tidak dapat diubah berarti bahwa (seperti di atas) tabel hash tidak perlu membuat salinan kunci hash setiap kali. Jika string bisa berubah, dan tabel hash tidak membuat ini, itu mungkin untuk sesuatu untuk mengubah kunci hash di kejauhan.
Cara Obyek di java bekerja, adalah bahwa semuanya memiliki kunci hash (diakses melalui metode hashCode ()). Memiliki string yang tidak dapat diubah berarti kode hash dapat di-cache. Mempertimbangkan seberapa sering String digunakan sebagai kunci hash, ini memberikan dorongan kinerja yang signifikan (daripada harus menghitung ulang kode hash setiap kali).
Substring
Dengan membuat String tidak berubah, array karakter yang mendasari yang mendukung struktur data juga tidak berubah. Hal ini memungkinkan untuk optimasi tertentu pada substring
metode yang dilakukan (tidak harus dilakukan - juga memperkenalkan kemungkinan beberapa kebocoran memori juga).
Jika kamu melakukan:
String foo = "smiles";
String bar = foo.substring(1,5);
Nilai bar
adalah 'mil'. Namun, keduanya foo
dan bar
dapat didukung oleh array karakter yang sama, mengurangi instantiation dari lebih banyak array karakter atau menyalinnya - hanya menggunakan titik awal dan akhir yang berbeda dalam string.
foo | | (0, 6)
ay
tersenyum
^ ^
bar | | (1, 5)
Sekarang, kelemahan dari itu (kebocoran memori) adalah bahwa jika seseorang memiliki string panjang 1k dan mengambil substring dari karakter pertama dan kedua, itu juga akan didukung oleh array karakter panjang 1k. Array ini akan tetap ada di memori bahkan jika string asli yang memiliki nilai seluruh array karakter adalah sampah yang dikumpulkan.
Orang dapat melihat ini dalam String dari JDK 6b14 (kode berikut ini dari sumber GPL v2 dan digunakan sebagai contoh)
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.offset = 0;
this.count = count;
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
Perhatikan bagaimana substring menggunakan konstruktor String tingkat paket yang tidak melibatkan penyalinan array dan akan jauh lebih cepat (dengan mengorbankan kemungkinan menjaga sekitar beberapa array besar - meskipun tidak menduplikasi array besar juga).
Perhatikan bahwa kode di atas adalah untuk Java 1.6. Cara konstruktor substring diimplementasikan telah diubah dengan Java 1.7 seperti yang didokumentasikan dalam Changes to String representasi internal yang dibuat di Java 1.7.0_06
- masalah bing yang kehabisan memori kebocoran yang saya sebutkan di atas. Java kemungkinan tidak dilihat sebagai bahasa dengan banyak manipulasi String dan karenanya peningkatan kinerja untuk substring adalah hal yang baik. Sekarang, dengan dokumen XML besar yang disimpan dalam string yang tidak pernah dikumpulkan, ini menjadi masalah ... dan dengan demikian perubahan menjadi String
tidak menggunakan array mendasar yang sama dengan substring, sehingga array karakter yang lebih besar dapat dikumpulkan lebih cepat.
Jangan menyalahgunakan Stack
Seseorang dapat meneruskan nilai string di sekitar daripada referensi ke string yang tidak dapat diubah untuk menghindari masalah dengan kemampuan berubah-ubah. Namun, dengan string besar, meneruskan ini pada stack akan menjadi ... kasar ke sistem (menempatkan seluruh dokumen xml sebagai string pada stack dan kemudian melepasnya atau melanjutkan untuk meneruskannya ...).
Kemungkinan deduplikasi
Memang, ini bukan motivasi awal untuk mengapa String harus abadi, tetapi ketika seseorang melihat rasional mengapa String abadi adalah hal yang baik, ini tentu saja sesuatu yang perlu dipertimbangkan.
Siapa pun yang pernah bekerja dengan Strings sedikit tahu bahwa mereka dapat menyedot memori. Ini terutama benar ketika Anda melakukan hal-hal seperti menarik data dari database yang bertahan sebentar. Berkali-kali dengan sengatan ini, mereka adalah string yang sama berulang-ulang (satu kali untuk setiap baris).
Banyak aplikasi Java skala besar saat ini mengalami hambatan memori. Pengukuran telah menunjukkan bahwa sekitar 25% dari Java heap live set data dalam jenis aplikasi ini dikonsumsi oleh objek String. Lebih jauh, kira-kira setengah dari objek String tersebut adalah duplikat, di mana duplikat berarti string1.equals (string2) benar. Memiliki duplikat objek String pada heap, pada dasarnya, hanya membuang-buang memori. ...
Dengan Java 8 pembaruan 20, JEP 192 (motivasi dikutip di atas) sedang dilaksanakan untuk mengatasi ini. Tanpa masuk ke dalam perincian tentang bagaimana deduplikasi string bekerja, adalah penting bahwa String itu sendiri tidak dapat diubah. Anda tidak dapat menduplikat StringBuilders karena mereka dapat berubah dan Anda tidak ingin seseorang mengubah sesuatu dari bawah Anda. Immutable Strings (terkait dengan string pool) berarti Anda dapat melewati dan jika Anda menemukan dua string yang sama, Anda dapat mengarahkan satu string referensi ke yang lain dan membiarkan pengumpul sampah mengkonsumsi yang baru saja tidak digunakan.
Bahasa lainnya
Objective C (yang mendahului Java) memiliki NSString
dan NSMutableString
.
C # dan .NET membuat pilihan desain yang sama dari string default menjadi tidak berubah.
String Lua juga tidak berubah.
Python juga.
Secara historis, Lisp, Skema, Smalltalk semua magang string dan dengan demikian membuatnya tidak berubah. Bahasa dinamis yang lebih modern sering menggunakan string dengan cara yang mengharuskan mereka tidak dapat diubah (mungkin bukan String , tetapi tidak dapat diubah).
Kesimpulan
Pertimbangan desain ini telah dibuat berulang kali dalam banyak bahasa. Ini adalah konsensus umum bahwa string tidak dapat diubah, untuk semua kecanggungan mereka, lebih baik daripada alternatif dan mengarah pada kode yang lebih baik (lebih sedikit bug) dan lebih cepat dieksekusi secara keseluruhan.