Mengapa Java String tidak memiliki metode manipulasi string statis?

17

Mengapa desainer Java tidak membuat versi statis metode manipulasi string di java.lang.Stringkelas? Metode berikut adalah apa yang saya rujuk, tetapi pertanyaannya dapat diperluas ke metode non-statis lainnya di kelas juga.

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

Hanya memiliki versi non-statis dari metode ini memaksa pemeriksaan null secara eksplisit di mana saja metode seperti itu harus dipanggil. Misalnya, hanya dengan memanggil saja example = example.trim()akan mengarah ke NullPointerException jika String example = null. Jadi programmer harus melakukan cek kosong boilerplate berikut:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

Saya akan membayangkan akan jauh lebih nyaman jika Stringmemiliki versi statis dari metode ini (mungkin bahkan secara eksklusif ), yang akan menggunakan string input sebagai argumen pertama:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

Ini akan menyebabkan kode bersih yang ditulis oleh programmer yang akan secara otomatis menangani kasus nol dengan hanya mengembalikan nol, daripada memaksa programmer untuk secara eksplisit menangani kasus nol. The kembali dari nol masuk akal bagi saya karena memanipulasi nol string yang harus menghasilkan nol tali, bukan kesalahan.

Mengapa desainer Java tidak memikirkan ini ketika mereka mendesain Stringkelas di Java 1 atau Java 2, atau bahkan menambahkan fungsi seperti itu di versi Java yang lebih baru?

ADTC
sumber
17
Saya akan menyarankan mengganti "Mengapa desainer Java tidak memikirkan X" dengan "Mengapa desainer Java memutuskan menentang X". Beri mereka kredit dasar untuk tidak buta terhadap opsi.
Avner Shahar-Kashtan
5
nulladalah keadaan luar biasa dan harus ditangani secara eksplisit.
CodesInChaos
2
@KonradMorawski: Secara pribadi saya menemukan bahwa penyalahgunaan metode ekstensi. Jika Anda memiliki nilai nol maka apa yang Anda lakukan mencoba memanggil metode di atasnya, Anda hanya akan membingungkan semua orang yang membaca kode itu. Itu implementasi ulang yang buruk dari suatu Maybe<T>jenis, saya kira?
Phoshi
1
@ Phoshi kita harus ingat bahwa metode ekstensi BUKAN metode nyata, mereka hanya gula sintaks. Tetapi saya setuju bahwa ini kontroversial. Saya berharap C # / Java menawarkan semacam sintaksis nol-keamanan bawaan, seperti - katakan - Kotlin. string name = employee?.personalData?.name. Sama seperti jalan pintas untuk semua pengulangan ini if (employee != null). Pertanyaan SO terkait: stackoverflow.com/questions/1196031/…
Konrad Morawski
2
@ADTC Erm, Anda menyadari bahwa suatu program tidak dapat memprediksi sebelumnya bahwa suatu nilai adalah nol, bukan? - Anda harus mendefinisikan kontrak antara antarmuka Anda sedemikian rupa sehingga Anda dapat yakin apakah suatu nilai diperbolehkan nol atau tidak. Mengecek kosong di mana-mana berarti Anda memiliki masalah desain program.
Uooo

Jawaban:

30

Kembalinya nol masuk akal bagi saya karena memanipulasi string nol harus menghasilkan string nol, bukan kesalahan

Nah, itu pendapat Anda . Orang lain mungkin berpendapat bahwa operasi String pada objek nol, yang tidak mengandung String, tidak masuk akal dan karenanya harus membuang Pengecualian

Mengapa "desainer Java" melakukan atau tidak melakukan sesuatu yang sulit dijawab.

Sudah ada perpustakaan di luar sana yang dapat melakukan operasi String null-safe, misalnya StringUtils dari Apache Commons. Anda dapat menggunakan itu atau perpustakaan serupa jika Anda membutuhkannya.


Penambahan berdasarkan komentar Anda

Membaca komentar, sepertinya masalah sebenarnya yang Anda hadapi adalah Anda harus memeriksa nullseluruh kode Anda. Itu bisa menjadi indikator dari desain program yang buruk tanpa kontrak yang jelas antara antarmuka. Anda mungkin ingin membaca Menghindari pernyataan "! = Null" di Jawa?

Uooo
sumber
1
Terima kasih atas tanggapan Anda. Saya kira pertanyaan sebenarnya adalah, mengapa kita harus bergantung pada perpustakaan eksternal atau kelas buatan sendiri ketika fitur dasar seperti itu dapat menjadi bagian dari Java standar?
ADTC
4
@ADTC mari kita ajukan pertanyaan sebaliknya: Mengapa "desainer Java" harus memasukkan sesuatu ke dalam bahasa, jika sudah ada banyak perpustakaan yang bagus di luar sana, diuji dan didokumentasikan dengan baik? Cara mendefinisikan "fitur dasar" didasarkan pada pendapat. Bukankah sebagian besar setiap proyek memerlukan pustaka eksternal untuk "Fungsionalitas dasar" (pengujian unit, mengejek, tanggal dan waktu, ...)? Ini bukan masalah besar, kan?
Uooo
Salah satu cara menangani null adalah dengan menggunakan Guava Optional- code.google.com/p/guava-libraries/wiki/…
Konrad Morawski
10

IMO keseluruhan "jika arg adalah null kembali null" pendekatan untuk menulis metode tidak perlu meningkatkan kompleksitas siklus program Anda.

Libo Java awal menggunakan pendekatan return null, tetapi orang-orang JDK selalu dijaga terhadap null dengan pengecualian.

Dengan waktu, saya pikir pendekatan yang terakhir telah keluar sebagai pemenang yang jelas.

Mengapa? Karena bidang nol memecah banyak prinsip oo. Anda tidak bisa memperlakukan mereka sebagai anggota kelas polimorfik. Ini berarti bahwa Anda selalu harus kode kasus khusus untuk null, dan karenanya kompleksitas siklomatik Anda melonjak ketika Anda harus menganggap bahwa hal-hal dapat menjadi nol.

Untuk menyelesaikan masalah Anda, pertimbangkan untuk menggunakan pola objek nol daripada mengandalkan bidang nol.

Alexander Torstling
sumber
2
Tetapi Stringbukankah polimorfik, bukan? Dan bagaimana Anda menggunakan pola objek nol untuk tipe yang sudah ada seperti String?
svick
String bukan polimorfik, tidak. Tetapi meskipun demikian Anda ingin tahu bahwa Anda dapat memanggil metode instance pada referensi string apa pun yang Anda miliki. Ini berfungsi untuk semua referensi yang bukan nol. String sudah memiliki objek nol: string kosong. Sama seperti daftar memiliki daftar kosong. Jadi tanyakan pada diri Anda mengapa string kosong tidak cukup dalam kasus Anda. Saya kira Anda menggunakan string nol untuk menandai beberapa kasus khusus. Tanyakan pada diri Anda apakah Anda dapat menggunakan bendera terpisah untuk kasing khusus itu.
Alexander Torstling
@AlexanderTorstling: Bidang jenis intdefault ke nol daripada null. Secara konseptual, dimungkinkan untuk memiliki stringtipe yang nilai defaultnya adalah string kosong daripada null[tipe seperti itu semantik Stringapa intyang harus Integer]. Fakta bahwa non-kosong stringakan secara internal memegang referensi ke objek tumpukan akan menjadi detail implementasi; tidak ada alasan ia tidak bisa berperilaku semantik seperti primitif.
supercat
@supercat: Setuju. Saya pikir akan lebih baik untuk melarang nilai null untuk refefences kecuali jika diaktifkan secara eksplisit. Bidang non-null dan final default. Banyak tipe sudah memiliki objek perilaku nol
Alexander Torstling
@AlexanderTorstling: Memiliki lokasi penyimpanan dari semua jenis standar untuk semua-byte-nol, dan dengan ketentuan bahwa jenis struktur dapat ditetapkan melalui semua-byte-salinan, sangat menyederhanakan kerangka kerja, tetapi cukup banyak menyiratkan bahwa jenis dengan semantik referensi yang dapat diubah harus default ke batal. Namun, akan sangat membantu jika memiliki dukungan kerangka kerja untuk tipe nilai yang akan merangkum satu referensi dan akan "kotak" sebagai - dan dapat membuka kotak dari - tipe referensi itu .
supercat
3

Tidak mengatakan ini alasannya, tetapi kecuali untuk toString, semua metode ini dengan mudah dikemas dalam kelas pembantu statis, sedangkan kebalikannya tidak benar.

Yaitu jika Anda ingin Stings.toUpper (input string) kode untuk itu mudah untuk ditulis, tetapi jika Anda ingin instance.toUpper dan semua yang Anda miliki adalah String.toUpper, well, itu tidak mungkin ... kecuali mereka memperkenalkan metode ekstensi, yang kemungkinan besar bahkan tidak dipertimbangkan pada saat itu.

jmoreno
sumber
Poin bagus, meskipun lebih banyak komentar daripada jawaban. Tetapi bahkan mengingat itu, mengapa kita harus bergantung pada perpustakaan eksternal atau kelas buatan sendiri ketika fitur dasar seperti itu dapat menjadi bagian dari Java standar?
ADTC
2
Sampai sekarang, Anda memiliki String.format(statis), tetapi Anda tidak dapat melakukannya "something %s".format(id).
Konrad Morawski
@adtc: karena ini bukan fitur dasar bahasa untuk melakukannya melalui kelas statis. Mulai dari premis itu, ada banyak alasan untuk tidak melakukannya - kode / kode yang tidak perlu, fungsi duplikat, biaya pengembangan / pemeliharaan.
jmoreno
-2

Dalam java, string itu adalah objek. Itu pilihan desain.

Referensi objek bisa nol dan nol jika tidak ada objek yang ditugaskan padanya. Jika Anda memanggil objek seperti itu, NullPointerException dilemparkan. Itu perilaku standar.

Desainer Java membuat pilihan memiliki string sebagai objek dan memiliki metode yang melempar pengecualian null-pointer adalah apa yang Anda dapatkan jika Anda ingin string menjadi objek.

Mengapa desainer Java tidak memikirkan ini ketika mereka mendesain kelas String di Java 1 atau Java 2, atau bahkan menambahkan fungsi seperti itu di versi Java yang lebih baru?

Mereka mungkin memang memikirkannya dan memilih untuk menggabungkan perilaku-o.

Pieter B
sumber
Boleh saya tahu, bagaimana cara membuat metode statis untuk menangani kasus nol bukan perilaku OO ? Untuk menjadi jelas, saya tidak mengatakan itu, tapi saya mencoba untuk memahami mengapa Anda mengatakan keputusan desain adalah menggabungkan perilaku OO.
ADTC
Metode statis lebih mirip fungsi. Dan untuk penggunaan yang Anda inginkan mereka bahkan tidak boleh menjadi bagian dari kelas string melainkan menjadi bagian dari beberapa kelas utilitas. Sama seperti fungsi kelas matematika.
Pieter B
4
Hanya karena string adalah objek, bukan berarti kelas String tidak dapat memiliki metode statis. Dan memang sudah memiliki beberapa, misalnya. String.format. (Sama dalam C #, by the way). Jadi jika itu pilihan desain, itu tidak bisa semata-mata berasal dari fakta bahwa string adalah objek, dan itu tidak diterapkan secara konsisten.
Konrad Morawski
@PieterB Saya tidak akan mengeluh jika setidaknya metode seperti itu disediakan di Stringskelas utilitas, seperti kita memiliki Arrayskelas utilitas ( meskipun saya mengerti itu dibuat karena kebutuhan semata-mata karena array menjadi semacam persilangan aneh antara primitif dan objek: ) ) .. selama itu adalah bagian dari Java standar dan tidak memerlukan dependensi.
ADTC