Mengapa tidak ada String.Empty di Jawa?

260

Saya mengerti bahwa setiap kali saya mengetik string literal "", objek String yang sama direferensikan dalam kumpulan string.

Tetapi mengapa String API tidak menyertakan a public static final String Empty = "";, jadi saya bisa menggunakan referensi String.Empty?

Ini akan menghemat waktu kompilasi, paling tidak, karena kompiler akan tahu untuk mereferensikan String yang ada, dan tidak perlu memeriksa apakah itu telah dibuat untuk digunakan kembali, kan? Dan secara pribadi saya pikir proliferasi string literal, terutama yang kecil, dalam banyak kasus adalah "bau kode".

Jadi ada Grand Design Reason di balik tidak ada String.Empty, atau apakah pembuat bahasa tidak berbagi pandangan saya?

Tom Tresansky
sumber
5
Aidanc: Saya pikir dia berarti situasi di mana Anda melakukan hal-hal seperti outputBlah = "", dan ia mungkin lebih suka something == String.Emptylebih something.Length > 0juga (Anda melewatkan cek nol.)
Skurmedel
2
@Aidanc - Dia mencari "anggota kosong" seperti Collections.EMPTY_SET , bukan fungsi untuk memeriksa string "kekosongan".
Tim Stone
2
@Aidanc: Apa yang mengilhami ini sebenarnya 'TextBox.setText ("");'.
Tom Tresansky
3
Ada String.isEmpty()fungsi ... mengapa kamu mau String.EMPTY?
Buhake Sindi
8
String.isEmpty()tidak mengembalikan string kosong.
Steve Kuo

Jawaban:

191

String.EMPTYadalah 12 karakter, dan ""dua, dan keduanya akan merujuk persis contoh yang sama dalam memori saat runtime. Saya tidak sepenuhnya yakin mengapa String.EMPTYakan menghemat waktu kompilasi, pada kenyataannya saya pikir itu akan menjadi yang terakhir.

Terutama mengingat Strings tidak dapat diubah, ini tidak seperti Anda pertama-tama bisa mendapatkan String kosong, dan melakukan beberapa operasi di atasnya - terbaik untuk menggunakan StringBuilder(atau StringBufferjika Anda ingin menjadi thread-safe) dan mengubahnya menjadi String.

Perbarui
Dari komentar Anda ke pertanyaan:

Yang menginspirasi ini sebenarnya TextBox.setText("");

Saya percaya akan sepenuhnya sah untuk memberikan konstanta di kelas yang sesuai:

private static final String EMPTY_STRING = "";

Dan kemudian referensi seperti dalam kode Anda sebagai

TextBox.setText(EMPTY_STRING);

Karena dengan cara ini, setidaknya Anda secara eksplisit menyatakan bahwa Anda menginginkan sebuah String kosong, daripada Anda lupa untuk mengisi String di IDE Anda atau sesuatu yang serupa.

Noel M
sumber
14
Saya akan tetap memberi Anda +1, tetapi saya merasa kotor karena Anda menyebutkan StringBuildertanpa membicarakan tentang bagaimana sembilan dari sepuluh itu benar-benar tidak sesuai untuk digunakan StringBuilderdaripada penggabungan.
Randolpho
85
Saya cenderung lebih suka string.empty, terutama karena lebih eksplisit. Juga, ada situasi nilai di mana bisa lebih sulit untuk membedakan secara visual "" dan hal-hal seperti "'". Pada akhirnya seperti yang orang lain catat, itu hanyalah salah satu dari gaya gaya yang tidak berarti yang memberi kita makanan untuk diperdebatkan ketika kita bosan dengan pekerjaan nyata. =)
JohnFx
@Nodel M: Mengenai waktu kompilasi, saya akan berasumsi bahwa jika ada 2 string literal yang didefinisikan dalam 2 file sumber yang berbeda dengan nilai string yang sama, ketika kompiler mencapai yang ke-2 ia perlu melakukan semacam pemeriksaan untuk mencari tahu " hei, saya sudah tahu tentang string ini dari belakang ke sini ". Saya diakui bukan ahli dalam kompiler java, tapi bagaimana ini BUKAN terjadi? Dan saya akan berpikir melewatkan cek itu akan menghasilkan peningkatan sangat kecil dalam waktu kompilasi.
Tom Tresansky
@ Tom - Saya percaya String interning dilakukan saat runtime, bukan waktu kompilasi, jadi sebenarnya jika Anda memiliki string kosong sebagai konstanta di file lain, kompiler perlu merujuk kelas tersebut untuk menyelesaikan String literal.
Noel M
1
@ Randolpho Saat menggunakan rangkaian string, Anda sebenarnya menggunakan StringBuilder di bawah tenda.
whiskeysierra
133

Menggunakan org.apache.commons.lang.StringUtils.EMPTY

giok
sumber
30
Terlihat jauh lebih bagus dan lebih mudah dibaca daripada "" kosong. Saya harap itu bukan hanya saya.
Lakatos Gyula
2
@LakatosGyula - Saya pikir itu mungkin (hanya Anda). Pemrogram Java mahir tidak memiliki masalah membaca ""... dan sebagian besar mungkin akan keberatan keras tentang penggunaan EMPTYkecuali dalam situasi tertentu di mana EMPTYmemiliki makna domain spesifik. (Dan dalam kasus seperti itu, mungkin ada nama yang lebih tepat.)
Stephen C
14
@LakatosGyula Bukan hanya kamu. Saya beralih dari Java ke pengembangan .NET, dan String.Empty adalah fitur yang saya senang temukan di framework. Saya suka sifat eksplisit itu lebih dari satu set kutipan kosong.
yohohoho
64
@StephenC Ketika saya melihat "" yang kosong hal pertama terlintas dalam pikiran saya bahwa itu adalah bug, seseorang tidak menyelesaikan fungsi dll. Dengan String.EMPTY Saya tahu persis bahwa pengembang bermaksud mengembalikan string kosong.
Lakatos Gyula
1
Juga membantu untuk semua saat-saat ketika linter mengatakan "gunakan konstanta bernama bukannya bla bla bla". Setiap programmer tahu "" bukan sihir, tetapi tidak harus menjelaskannya kepada pelanggan lebih baik.
LizH
28

Jika Anda ingin membandingkan dengan string kosong tanpa khawatir tentang nilai null Anda dapat melakukan hal berikut.

if ("".equals(text))

Pada akhirnya Anda harus melakukan apa yang menurut Anda paling jelas. Kebanyakan pemrogram menganggap "" artinya string kosong, bukan string yang seseorang lupa untuk memasukkan apa pun ke dalamnya.

Jika Anda berpikir ada keuntungan kinerja, Anda harus mengujinya. Jika Anda tidak berpikir layak untuk menguji diri sendiri, itu indikasi yang baik itu benar-benar tidak layak.

Sepertinya Anda mencoba menyelesaikan masalah yang diselesaikan saat bahasa tersebut dirancang lebih dari 15 tahun yang lalu.

Peter Lawrey
sumber
1
Saya sangat terlambat ke pesta tetapi, karena string Java tidak dapat diubah, saya percaya bahwa semua string kosong dalam JVM hanyalah referensi yang berbeda untuk objek String yang sama. Jadi sederhananya yang berikut ini juga benar: if ("" == text)
Ajoy Bhatia
12
@AjoyBhatia Masalahnya adalah Anda dapat membuat string kosong baru. if ("" == new String())itu salah. Tes yang lebih baikif(text.isEmpty())
Peter Lawrey
1
@AjoyBhatia - Hanya jika string diinternir. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Jika Anda benar-benar menginginkan konstanta String.EMPTY, Anda dapat membuat kelas akhir statis utilitas bernama "Constants" (misalnya) dalam proyek Anda. Kelas ini akan mempertahankan konstanta Anda, termasuk String kosong ...

Dalam ide yang sama, Anda dapat membuat NOL, SATU konstanta int ... yang tidak ada di kelas Integer, tetapi seperti yang saya komentari, akan merepotkan menulis dan membaca:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

Dll

Benoit Courtine
sumber
8

Apache StringUtils mengatasi masalah ini juga.

Gagal dari opsi lain:

  • isEmpty () - bukan null safe. Jika string adalah nol, melempar NPE
  • length () == 0 - lagi bukan nol aman. Juga tidak memperhitungkan string spasi putih akun.
  • Perbandingan dengan konstanta KOSONG - Mungkin tidak nol aman. Masalah spasi putih

Granted StringUtils adalah pustaka lain untuk diseret, tetapi berfungsi dengan sangat baik dan menghemat banyak waktu dan kerumitan memeriksa nol atau menangani NPE dengan anggun.

Freiheit
sumber
3
sehingga ... tampaknya satu-satunya pilihan yang aman adalah kondisi Yoda mengerikan: "".equals(s)?
Lie Ryan
8

Jangan hanya mengatakan "kumpulan memori string digunakan kembali dalam bentuk literal, case closed". Apa yang dilakukan oleh kompiler di bawah tenda bukanlah intinya di sini. Pertanyaannya masuk akal, terutama mengingat jumlah suara yang diterima.

Ini tentang simetri , tanpanya API lebih sulit digunakan untuk manusia. SDK Jawa awal terkenal mengabaikan aturan dan sekarang sudah agak terlambat. Berikut adalah beberapa contoh di atas kepala saya, jangan ragu untuk chip dalam contoh "favorit" Anda:

  • BigDecimal.ZERO, tapi tidak ada AbstractCollection.EMPTY, String.EMPTY
  • Array.length tapi List.size ()
  • List.add (), Set.add () tetapi Map.put (), ByteBuffer.put () dan jangan lupa StringBuilder.append (), Stack.push ()
Slawomir
sumber
Bahkan jika Anda menamai panjang parameter Daftar () Anda masih membutuhkan tanda kurung karena ini adalah metode. Array.length adalah variabel final publik, yang hanya berfungsi karena Array tidak dapat diubah. Jadi, Anda masih memiliki Array.length dan List.length (). Saya berpendapat bahwa ini lebih membingungkan dan cenderung kesalahan. Adapun .append () dan .push (), sementara mereka melakukan tugas yang sama, saya pikir mereka benar dinamai. Menambahkan String adalah persis apa yang Anda lakukan, tetapi Anda tidak "menambahkan" Stack, Anda mendorong dan mengeluarkan nilai. Dan StringBuilder.push () akan menyiratkan StringBuilder.pop (), yang tidak mungkin.
Craig Parton
Berasal dari templat / generik, antarmuka yang konsisten membantu algoritma juga. Jika suatu algoritma membutuhkan panjang koleksi, panjang (T) atau T.length () adalah semua yang kami pedulikan. Demikian pula, menambahkan ke ujung tumpukan, daftar atau string dapat dilakukan dengan add universal () atau append (). Anda menyebutkan bahwa array di Java adalah tipe tidak berubah / builtin dengan properti panjang terpapar. Itu bagus, bukan berarti kompiler tidak dapat menangani atau menghasilkan kode untuk length (T) atau T.length (). Kotlin menghasilkan sejumlah metode intrinsik untuk berbagai kasus.
Slawomir
Tetapi metode length () yang bernama secara konsisten hanya memungkinkan kita memeriksa panjang. Seberapa bermanfaatkah itu? Jika tujuan Anda adalah untuk mengabstraksikan Daftar dan Array agar dapat digunakan dengan cara apa pun melalui antarmuka, Anda juga memerlukan cara yang konsisten untuk membaca atau menulis data. Jadi sekarang Anda perlu menghasilkan metode get (), set (), dan tambahkan (). Pada dasarnya, Anda membuat tampilan Daftar Array yang kurang fungsional. Karena Arrays.asList () tersedia, mudah digunakan, dan ringan, mengapa menciptakan kembali kemudi? Array, Daftar, StringBuilders, dan Stacks semuanya memiliki tujuan tertentu. Tampaknya lebih baik mendesain antarmuka Anda untuk menggunakan yang paling cocok.
Craig Parton
5

Semua ""literal itu adalah objek yang sama. Mengapa membuat semua kompleksitas ekstra itu? Hanya lebih lama untuk mengetik dan kurang jelas (biaya untuk kompiler minimal). Karena string Java adalah objek yang tidak dapat diubah, tidak perlu sama sekali untuk membedakannya kecuali mungkin sebagai hal yang efisien, tetapi dengan string kosong literal itu bukan masalah besar.

Jika Anda benar-benar menginginkan EmptyStringkonstanta, buatlah sendiri. Tetapi yang harus dilakukan hanyalah mendorong kode verbose yang lebih banyak; tidak akan pernah ada manfaat untuk melakukannya.

Donal Fellows
sumber
27
x = String.Emptymenyampaikan maksud lebih baik daripada x = "". Yang terakhir ini bisa merupakan kelalaian yang tidak disengaja. Mengatakan bahwa tidak pernah ada manfaat adalah salah.
Jeffrey L Whitledge
@ Jeffrey: Saya rasa saya tidak terlalu setuju. Itu salah satu dari hal-hal ini di mana tidak ada aturan yang keras dan cepat kurasa.
Donal Fellows
Ya, penting untuk menunjukkan bahwa kompiler java memeriksa apakah string literal sudah ada sebelum membuat instance baru di kumpulan string.
rds
1
@ Jeffrey - mengetahui bahwa ini adalah diskusi yang sangat lama dan subyektif. x = String.Emptymenyampaikan maksud, benar. Tapi anggaplah bahasanya memberikan konstanta String.Empty, ketika Anda bertemu x = ""Anda masih tahu persis sebanyak tentang niat seolah-olah tidak ada konstan seperti itu. Anda akan perlu menjamin bahwa semua tempat di dunia kode Java di mana string kosong itu intendet tidak digunakan ""untuk mendapatkan informasi yang Anda sebutkan. Ironisnya, C # menggunakan konstanta dan mendorong penggunaannya, jadi seperti yang saya katakan, saya tahu ini adalah diskusi yang sangat diperdebatkan.
chiccodoro
@chiccodoro - Ya, itu benar. Itu sebabnya string kosong literal ""harus ilegal, untuk mengesampingkan kecelakaan. Aku bercanda!
Jeffrey L Whitledge
4

Untuk menambahkan apa yang dinyatakan Noel M, Anda dapat melihat pertanyaan ini, dan jawaban ini menunjukkan bahwa konstanta digunakan kembali.

http://forums.java.net/jive/message.jspa?messageID=17122

Konstanta string selalu "diinternir" sehingga tidak ada kebutuhan untuk konstanta tersebut.

String s=""; String t=""; boolean b=s==t; // true
James Black
sumber
1
tautannya sudah mati.
pelaku diet
3

Saya mengerti bahwa setiap kali saya mengetikkan String literal "", objek String yang sama dirujuk dalam kumpulan String.
Tidak ada jaminan yang dibuat. Dan Anda tidak dapat mengandalkan itu di aplikasi Anda, itu sepenuhnya tergantung jvm untuk memutuskan.

atau apakah pembuat bahasa tidak membagikan pandangan saya?
Ya. Bagi saya, sepertinya hal prioritas sangat rendah.

Nikita Rybak
sumber
6
Tidak ada jaminan seperti itu dibuat ... Yah, JLS memang menyatakan yang seharusnya terjadi.
Tim Stone
@Tim Tidak, kecuali jika Anda membuat panggilan 'magang'. Sangat mudah untuk membangun dua string besar yang sama secara pemrograman dan memeriksa.
Nikita Rybak
@Tim Sebagai contoh, ulangi + = "a"; 100 kali, lakukan hal yang sama dengan b dan periksa.
Nikita Rybak
5
Anda benar, tetapi yang Anda uraikan bukanlah string literal, atau ekspresi yang hasilnya dapat dijamin pada waktu kompilasi (seperti String username = "Bob" + " " + "Smith";). String yang dibuat secara pemrograman tidak memiliki jaminan diinternir, kecuali jika Anda secara eksplisit menelepon intern()seperti yang telah Anda nyatakan. Skenario OP menjelaskan penggunaan string kosong literal di ""seluruh kode, yang merupakan kasus di mana pemagangan otomatis akan terjadi.
Tim Stone
@Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Sekarang adan barahkan ke lokasi memori yang sama di PermGen. Lihat artikel ini
1ac0
1

Jawaban terlambat, tapi saya pikir itu menambah sesuatu yang baru untuk topik ini.

Tidak ada jawaban sebelumnya yang menjawab pertanyaan awal. Beberapa telah berusaha untuk membenarkan kurangnya konstanta, sementara yang lain telah menunjukkan cara di mana kita dapat menangani kekurangan konstanta. Tetapi tidak ada yang memberikan pembenaran yang meyakinkan untuk kepentingan konstanta, sehingga kekurangannya masih belum dijelaskan dengan baik.

Konstanta akan berguna karena akan mencegah kesalahan kode tertentu dari tanpa disadari.

Katakanlah Anda memiliki basis kode besar dengan ratusan referensi ke "". Seseorang memodifikasi salah satu dari ini sambil menggulir kode dan mengubahnya menjadi "". Perubahan seperti itu akan memiliki peluang besar untuk tidak diketahui dalam produksi, pada titik mana hal itu dapat menyebabkan beberapa masalah yang sumbernya sulit dideteksi.

OTOH, konstanta pustaka yang bernama KOSONG, jika mengalami kesalahan yang sama, akan menghasilkan kesalahan kompilator untuk sesuatu seperti EM PTY.

Menentukan konstanta Anda sendiri masih lebih baik. Seseorang masih dapat mengubah inisialisasi karena kesalahan, tetapi karena penggunaannya yang luas, dampak kesalahan seperti itu akan jauh lebih sulit untuk diketahui tanpa kesalahan daripada kesalahan dalam kasus penggunaan tunggal.

Ini adalah salah satu manfaat umum yang Anda dapatkan dari menggunakan konstanta alih-alih nilai literal. Orang biasanya menyadari bahwa menggunakan konstanta untuk nilai yang digunakan di banyak tempat memungkinkan Anda dengan mudah memperbarui nilai itu hanya di satu tempat. Apa yang jarang diakui adalah bahwa ini juga mencegah nilai dari modifikasi yang tidak disengaja, karena perubahan seperti itu akan terlihat di mana-mana. Jadi, ya, "" lebih pendek dari KOSONG, tetapi KOSONG lebih aman untuk digunakan daripada "".

Jadi, kembali ke pertanyaan awal, kita hanya bisa berspekulasi bahwa perancang bahasa mungkin tidak menyadari manfaat menyediakan konstanta untuk nilai-nilai literal yang sering digunakan. Mudah-mudahan, suatu hari nanti kita akan melihat konstanta string ditambahkan di Jawa.

Laurentiu Cristofor
sumber
-16

Bagi mereka yang mengklaim ""dan String.Emptydapat dipertukarkan atau yang ""lebih baik, Anda sangat salah.

Setiap kali Anda melakukan sesuatu seperti myVariable = ""; Anda membuat instance objek. Jika objek String Java memiliki konstanta publik KOSONG, hanya akan ada 1 instance dari objek ""

Misalnya: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (11 termasuk String.EMPTY) Pointer ke 1 objek

Atau: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 pointer ke 10 objek

Ini tidak efisien dan di seluruh aplikasi besar, bisa signifikan.

Mungkin kompiler Java atau run-time cukup efisien untuk secara otomatis mengarahkan semua "" instance ke instance yang sama, tetapi mungkin tidak dan membutuhkan pemrosesan tambahan untuk membuat penentuan itu.

Antony Booth
sumber
9
Salah, menurut stackoverflow.com/questions/1881922/… , string "" akan digunakan kembali dari kolam String.
RealHowTo
1
Saya menyatakan itu mungkin menggunakan kembali objek yang sama dan jika demikian, masih kurang efisien, karena perlu menemukan objek itu (dalam kumpulan string), jadi bagaimana saya salah? Apapun, ada beberapa alasan mengapa String.Empty lebih unggul, termasuk mencegah kesalahan seperti myVar = ""; dan keterbacaan serta peningkatan kinerja yang sudah saya nyatakan. Merupakan praktik yang baik untuk menggunakan konstanta alih-alih membuat string literal, jika tanpa alasan lain; lebih mudah untuk mempertahankan kode.
Antony Booth
1
Saya ragu bahwa argumen kinerja Anda valid karena JLS mengatakan bahwa konstanta akan diperlakukan sebagai literal pada waktu kompilasi ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ). Keterbacaan adalah argumen yang lebih baik.
RealHowTo
3
@AntonySmith - Saya kira Anda perlu sedikit mempelajari Java atau mungkin Anda sudah tahu kesalahan Anda sekarang. String Java tidak berubah dan di kolam. Jadi hanya ada SATU objek string untuk "" dalam JVM, tidak peduli berapa kali ditemukan dalam kode. Anda dapat memeriksa apakah senar kosong dengan melakukanif (text == "")
Ajoy Bhatia
2
Salah. Komentar ini harus dihapus.
Elad Tabak