Tại sao không có String.Empty trong Java?


260

Tôi hiểu rằng mỗi khi tôi nhập chuỗi ký tự "", cùng một đối tượng Chuỗi được tham chiếu trong nhóm chuỗi.

Nhưng tại sao API chuỗi không bao gồm a public static final String Empty = "";, vì vậy tôi có thể sử dụng tài liệu tham khảo String.Empty?

Nó sẽ tiết kiệm thời gian biên dịch, ít nhất, vì trình biên dịch sẽ biết tham chiếu Chuỗi hiện có và không phải kiểm tra xem nó đã được tạo để sử dụng lại chưa, phải không? Và cá nhân tôi nghĩ rằng sự phổ biến của các chuỗi ký tự, đặc biệt là các chuỗi nhỏ, trong nhiều trường hợp là "mùi mã".

Vì vậy, có một Lý do thiết kế lớn đằng sau không có String.Empty, hay những người sáng tạo ngôn ngữ chỉ đơn giản là không chia sẻ quan điểm của tôi?


5
Aidanc: Tôi nghĩ anh ấy có nghĩa là những tình huống mà bạn làm những thứ như thế outputBlah = "", và anh ấy có lẽ cũng thích something == String.Emptyhơn something.Length > 0(bạn bỏ qua một kiểm tra null.)
Skurmedel

2
@Aidanc - Anh ấy đang tìm kiếm một "thành viên trống rỗng" như Collections.EMPTY_SET , không phải là một chức năng để kiểm tra chuỗi "sự trống rỗng".
Tim Stone

2
@Aidanc: Điều truyền cảm hứng này thực sự là 'TextBox.setText ("");'.
Tom Tresansky

3
Có một String.isEmpty()chức năng ... tại sao bạn muốn String.EMPTY?
Buhake Sindi

8
String.isEmpty()không trả về một chuỗi rỗng.
Steve Kuo

Câu trả lời:


191

String.EMPTYlà 12 ký tự và ""là hai ký tự và cả hai sẽ tham chiếu chính xác cùng một thể hiện trong bộ nhớ khi chạy. Tôi không hoàn toàn chắc chắn tại sao String.EMPTYsẽ tiết kiệm thời gian biên dịch, thực tế tôi nghĩ nó sẽ là cái sau.

Đặc biệt là việc xem xét Stringlà không thay đổi, trước tiên bạn không thể có được một Chuỗi trống và thực hiện một số thao tác trên nó - tốt nhất là sử dụng StringBuilder(hoặc StringBuffernếu bạn muốn an toàn cho chuỗi) và biến chuỗi đó thành Chuỗi.

Cập nhật
Từ nhận xét của bạn cho câu hỏi:

Điều gì truyền cảm hứng này thực sự là TextBox.setText("");

Tôi tin rằng việc cung cấp một hằng số trong lớp thích hợp của bạn là hoàn toàn hợp pháp:

private static final String EMPTY_STRING = "";

Và sau đó tham chiếu nó như trong mã của bạn như

TextBox.setText(EMPTY_STRING);

Theo cách này, ít nhất bạn rõ ràng rằng bạn muốn có một Chuỗi trống, thay vì bạn quên điền Chuỗi vào IDE của mình hoặc một cái gì đó tương tự.


14
Tôi vẫn sẽ +1 bạn, nhưng tôi cảm thấy bẩn vì bạn đã đề cập StringBuildermà không nói về việc chín lần trong số mười điều đó hoàn toàn không phù hợp để sử dụng StringBuilderthay vì nối.
Randolpho

85
Tôi có xu hướng thích string.empty, chủ yếu là vì nó rõ ràng hơn. Ngoài ra, có những tình huống tỷ lệ khó phân biệt trực quan "" và những thứ như "'". Cuối cùng, như những người khác đã lưu ý, đó chỉ là một trong những điều vô nghĩa theo phong cách mà cho chúng ta thức ăn để tranh luận khi chúng ta chán công việc thực sự. =)
JohnFx

@Nodel M: Về thời gian biên dịch, tôi giả sử rằng nếu có 2 chuỗi ký tự được định nghĩa trong 2 tệp nguồn khác nhau có cùng giá trị chuỗi, khi trình biên dịch chạm vào lần thứ 2, nó cần thực hiện một số loại kiểm tra để tìm ra " này, tôi đã biết về chuỗi này từ đây rồi ". Tôi thừa nhận không có chuyên gia trong trình biên dịch java, nhưng làm thế nào điều này KHÔNG thể xảy ra? Và tôi nghĩ việc bỏ qua kiểm tra đó sẽ dẫn đến sự cải thiện rất nhỏ trong thời gian biên dịch.
Tom Tresansky

@Tom - Tôi tin rằng thực hiện chuỗi được thực hiện trong thời gian chạy, không phải biên dịch thời gian, vì vậy thực sự nếu bạn có chuỗi rỗng là một hằng số trong một tệp khác, trình biên dịch cần tham chiếu lớp đó để giải quyết theo chuỗi ký tự.
Noel M

1
@Randolpho Khi sử dụng nối chuỗi, bạn thực sự đang sử dụng StringBuilder dưới mui xe.
whiskeyierra

133

Sử dụng org.apache.commons.lang.StringUtils.EMPTY


30
Trông đẹp hơn và dễ đọc hơn một chữ "" trống. Tôi hy vọng nó không chỉ tôi.
Lakatos Gyula

2
@LakatosGyula - Tôi nghĩ rằng nó có thể (chỉ bạn). Các lập trình viên Java thành thạo không gặp vấn đề gì khi đọc ""... và hầu hết có lẽ sẽ phản đối lớn về việc sử dụng EMPTYngoại trừ trong các tình huống EMPTYcụ thể có ý nghĩa cụ thể của miền. (Và trong những trường hợp như vậy, có lẽ có một cái tên phù hợp hơn.)
Stephen C

14
@LakatosGyula Không chỉ có bạn. Tôi đã chuyển từ phát triển Java sang .NET và String.Empty là một tính năng tôi hài lòng tìm thấy trong khung. Tôi thích bản chất rõ ràng của nó trên một tập hợp các trích dẫn trống rỗng.
yohohoho

64
@StephenC Khi tôi thấy một "" trống ", điều đầu tiên tôi nghĩ rằng đó là một lỗi, ai đó chưa hoàn thành chức năng, v.v. Với String.EMPTY tôi biết chính xác rằng nhà phát triển dự định trả về một chuỗi trống.
Lakatos Gyula

1
Cũng hữu ích cho tất cả những lúc người nói dối nói "sử dụng hằng số được đặt tên thay vì blah blah blah". Mọi lập trình viên đều biết "" không phải là phép thuật, nhưng không phải giải thích điều đó với khách hàng thì tốt hơn.
LizH

28

Nếu bạn muốn so sánh với chuỗi rỗng mà không phải lo lắng về các giá trị null, bạn có thể làm như sau.

if ("".equals(text))

Cuối cùng, bạn nên làm những gì bạn tin là rõ ràng nhất. Hầu hết các lập trình viên đều cho rằng "" có nghĩa là chuỗi rỗng, không phải là chuỗi ai đó quên đặt bất cứ thứ gì vào.

Nếu bạn nghĩ rằng có một lợi thế về hiệu suất, bạn nên kiểm tra nó. Nếu bạn không nghĩ rằng nó đáng để thử nghiệm cho chính mình, thì đó là một dấu hiệu tốt cho thấy nó thực sự không đáng.

Có vẻ như bạn cố gắng giải quyết một vấn đề đã được giải quyết khi ngôn ngữ được thiết kế hơn 15 năm trước.


1
Tôi đến bữa tiệc khá muộn nhưng, vì các chuỗi Java là bất biến, tôi tin rằng tất cả các chuỗi trống trong JVM chỉ là các tham chiếu khác nhau cho cùng một đối tượng Chuỗi. Vì vậy, chỉ đơn giản như sau cũng đúng: if ("" == text)
Ajoy Bhatia

12
@AjoyBhatia Vấn đề là bạn có thể tạo các chuỗi trống mới. if ("" == new String())là sai. Một bài kiểm tra tốt hơnif(text.isEmpty())
Peter Lawrey

1
@AjoyBhatia - Chỉ khi các chuỗi được thực tập. stackoverflow.com/questions/10578984/what-is-opes-iterning
Davor

9

Nếu bạn thực sự muốn một hằng số String.EMPTY, bạn có thể tạo một lớp cuối cùng tĩnh tiện ích có tên "Hằng số" (ví dụ) trong dự án của bạn. Lớp này sẽ duy trì các hằng số của bạn, bao gồm cả Chuỗi trống ...

Trong cùng một ý tưởng, bạn có thể tạo ZERO, ONE int constants ... không tồn tại trong lớp Integer, nhưng như tôi đã nhận xét, sẽ rất khó để viết và đọc:

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

Vân vân.


8

Apache StringUtils cũng giải quyết vấn đề này.

Thất bại của các lựa chọn khác:

  • isEmpty () - không an toàn. Nếu chuỗi là null, ném NPE
  • length () == 0 - một lần nữa không null an toàn. Cũng không tính đến các chuỗi khoảng trắng.
  • So sánh với hằng số EMPTY - Có thể không an toàn. Vấn đề khoảng trắng

Được cấp StringUtils là một thư viện khác để kéo xung quanh, nhưng nó hoạt động rất tốt và tiết kiệm rất nhiều thời gian và kiểm tra rắc rối cho null hoặc xử lý NPE một cách duyên dáng.


3
vì vậy ... có vẻ như lựa chọn an toàn duy nhất là tình trạng Yoda khủng khiếp : "".equals(s)?
Lie Ryan

8

Đừng chỉ nói "nhóm bộ nhớ của chuỗi được sử dụng lại ở dạng nghĩa đen, trường hợp đóng". Những gì trình biên dịch làm dưới mui xe không phải là điểm ở đây. Câu hỏi là hợp lý, đặc biệt được đưa ra số lượng phiếu bầu nhận được.

Đó là về tính đối xứng , không có API thì khó sử dụng hơn cho con người. SDK Java ban đầu nổi tiếng đã bỏ qua quy tắc và bây giờ thì đã quá muộn. Dưới đây là một vài ví dụ trên đầu tôi, thoải mái để chip trong ví dụ "yêu thích" của bạn:

  • BigDecimal.ZERO, nhưng không có AbstractCollection.EMPTY, String.EMPTY
  • Array.length nhưng List.size ()
  • List.add (), Set.add () nhưng Map.put (), ByteBuffer.put () và chúng ta đừng quên StringBuilder.append (), Stack.push ()

Ngay cả khi bạn đặt tên cho độ dài tham số List (), bạn vẫn cần dấu ngoặc đơn vì đây là phương thức. Array.length là một biến cuối cùng công khai, nó chỉ hoạt động vì Mảng là bất biến. Vì vậy, bạn vẫn có Array.length và List.length (). Tôi sẽ tranh luận rằng khó hiểu hơn và dễ bị lỗi. Đối với .append () và .push (), trong khi chúng thực hiện các nhiệm vụ tương tự tôi nghĩ chúng được đặt tên thích hợp. Nối chuỗi là chính xác những gì bạn đang làm, nhưng bạn không "nối" một Stack, bạn đẩy và bật các giá trị. Và StringBuilder.push () sẽ ám chỉ StringBuilder.pop (), điều này là không thể.
Craig Parton

Đến từ các mẫu / generic, giao diện nhất quán cũng giúp với các thuật toán. Nếu một thuật toán cần độ dài của bộ sưu tập, độ dài (T) hoặc T.length () là tất cả những gì chúng tôi quan tâm. Tương tự, việc thêm vào cuối ngăn xếp, danh sách hoặc chuỗi có thể được thực hiện bằng một add () hoặc append () phổ quát. Bạn đã đề cập rằng mảng trong Java là loại không thay đổi / dựng sẵn với thuộc tính độ dài được hiển thị. Điều đó tốt, điều đó không có nghĩa là trình biên dịch không thể xử lý hoặc tạo mã cho độ dài (T) hoặc T.length (). Kotlin tạo ra một số phương pháp nội tại cho các trường hợp khác nhau.
Slawomir

Nhưng một phương thức length () được đặt tên nhất quán chỉ cho phép chúng ta kiểm tra độ dài. Làm thế nào là hữu ích? Nếu mục tiêu của bạn là Danh sách và Mảng trừu tượng để có thể sử dụng theo cách nào đó thông qua giao diện, bạn cũng cần một cách nhất quán để đọc hoặc ghi dữ liệu. Vì vậy, bây giờ bạn cần tạo các phương thức get (), set () và add (). Về cơ bản, bạn đang tạo một dạng xem Danh sách ít chức năng hơn của Mảng. Vì Arrays.asList () có sẵn, dễ sử dụng và nhẹ, tại sao phải phát minh lại bánh xe? Mảng, Danh sách, StringBuilders và Stacks đều có một mục đích cụ thể. Có vẻ tốt hơn để thiết kế giao diện của bạn để sử dụng phù hợp nhất.
Craig Parton

5

Tất cả những nghĩa ""đen là cùng một đối tượng. Tại sao làm cho tất cả thêm phức tạp? Nó chỉ dài hơn để gõ và ít rõ ràng hơn (chi phí cho trình biên dịch là tối thiểu). Vì các chuỗi của Java là các đối tượng bất biến, nên không bao giờ có nhu cầu phân biệt giữa chúng ngoại trừ có thể là một điều hiệu quả, nhưng với chuỗi ký tự trống thì đó không phải là vấn đề lớn.

Nếu bạn thực sự muốn một EmptyStringhằng số, hãy tự làm nó. Nhưng tất cả những gì nó sẽ làm là khuyến khích mã dài hơn nữa; sẽ không bao giờ có bất kỳ lợi ích để làm như vậy.


27
x = String.Emptytruyền đạt ý định tốt hơn x = "". Thứ hai có thể là một thiếu sót tình cờ. Để nói rằng không bao giờ có bất kỳ lợi ích là không chính xác.
Jeffrey L Whitledge

@Jeffrey: Tôi không nghĩ mình đặc biệt đồng ý. Đó là một trong những điều mà tôi cho rằng không có quy tắc cứng và nhanh nào.
Donal Fellows

Vâng, điều quan trọng là chỉ ra rằng trình biên dịch java kiểm tra xem chuỗi ký tự đã tồn tại hay chưa trước khi tạo một phiên bản mới trong nhóm chuỗi.
rds

1
@Jeffrey - biết rằng đây là một cuộc thảo luận rất cũ và chủ quan. x = String.Emptytruyền đạt ý định, đúng. Nhưng giả sử ngôn ngữ cung cấp một hằng số String.Empty, khi bạn gặp phải x = ""bạn vẫn biết chính xác nhiều về ý định như thể không có một hằng số như vậy. Bạn sẽ cần đảm bảo rằng tất cả các vị trí trong mã Java của thế giới nơi một chuỗi rỗng không được sử dụng ""để có được thông tin mà bạn đề cập. Trớ trêu thay, C # không sử dụng hằng số và khuyến khích việc sử dụng nó, vì vậy như tôi đã nói, tôi biết đó là một cuộc thảo luận rất hay.
chiccodoro

@chiccodoro - Vâng, đó là sự thật. Đó là lý do tại sao chuỗi trống rỗng ""nên là bất hợp pháp, để loại trừ tai nạn. Tôi đang đùa!
Jeffrey L Whitledge

4

Để thêm vào những gì Noel M đã nêu, bạn có thể xem câu hỏi này và câu trả lời này cho thấy hằng số được sử dụng lại.

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

Hằng chuỗi luôn luôn được "thực tập", do đó không thực sự cần một hằng số như vậy.

String s=""; String t=""; boolean b=s==t; // true

1
liên kết đã chết.
ăn kiêng

3

Tôi hiểu rằng mỗi khi tôi nhập chuỗi ký tự "", cùng một đối tượng Chuỗi được tham chiếu trong nhóm Chuỗi.
Không có sự đảm bảo nào được thực hiện. Và bạn không thể dựa vào nó trong ứng dụng của mình, hoàn toàn tùy thuộc vào quyết định.

hoặc những người sáng tạo ngôn ngữ chỉ đơn giản là không chia sẻ quan điểm của tôi?
Vâng. Đối với tôi, nó có vẻ là điều ưu tiên rất thấp.


6
Không có sự đảm bảo nào được thực hiện ... Chà, JLS không nêu rõ trường hợp đó.
Tim Stone

@Tim Không trừ khi bạn thực hiện cuộc gọi 'thực tập'. Thật dễ dàng để xây dựng hai chuỗi lớn bằng nhau lập trình và kiểm tra.
Nikita Rybak

@Tim Ví dụ: lặp lại a + = "a"; 100 lần, làm tương tự với b và kiểm tra.
Nikita Rybak

5
Bạn đúng, nhưng những gì bạn mô tả không phải là một chuỗi ký tự, cũng không phải là biểu thức có kết quả có thể được đảm bảo tại thời điểm biên dịch (chẳng hạn như String username = "Bob" + " " + "Smith";). Các chuỗi được tạo theo chương trình không có gì đảm bảo được thực tập, trừ khi bạn gọi rõ ràng intern()như bạn đã nêu. Kịch bản của OP mô tả bằng cách sử dụng chuỗi ký tự trống ""trong toàn bộ mã, đây là trường hợp xảy ra thực tập tự động.
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();Bây giờ abtrỏ đến cùng một vị trí bộ nhớ trong PermGen. Xem bài viết này
1ac0

1

Câu trả lời muộn, nhưng tôi nghĩ rằng nó thêm một cái gì đó mới cho chủ đề này.

Không có câu trả lời trước đã trả lời câu hỏi ban đầu. Một số đã cố gắng biện minh cho việc thiếu hằng số, trong khi những người khác đã chỉ ra những cách mà chúng ta có thể đối phó với việc thiếu hằng số. Nhưng không ai đưa ra một lời biện minh thuyết phục cho lợi ích của hằng số, vì vậy sự thiếu sót của nó vẫn chưa được giải thích chính xác.

Một hằng số sẽ hữu ích vì nó sẽ ngăn các lỗi mã nhất định không được chú ý.

Giả sử bạn có một cơ sở mã lớn với hàng trăm tham chiếu đến "". Ai đó sửa đổi một trong những điều này trong khi cuộn qua mã và thay đổi nó thành "". Một sự thay đổi như vậy sẽ có khả năng cao không được chú ý vào sản xuất, tại thời điểm đó nó có thể gây ra một số vấn đề mà nguồn của nó sẽ khó phát hiện.

OTOH, hằng số thư viện có tên EMPTY, nếu có cùng lỗi, sẽ tạo ra lỗi trình biên dịch cho một cái gì đó như EM PTY.

Xác định hằng số của riêng bạn vẫn tốt hơn. Ai đó vẫn có thể thay đổi khởi tạo do nhầm lẫn, nhưng do sử dụng rộng rãi, tác động của lỗi như vậy sẽ khó được chú ý hơn nhiều so với lỗi trong một trường hợp sử dụng.

Đây là một trong những lợi ích chung mà bạn nhận được từ việc sử dụng hằng số thay vì giá trị theo nghĩa đen. Mọi người thường nhận ra rằng việc sử dụng hằng số cho một giá trị được sử dụng ở hàng chục nơi cho phép bạn dễ dàng cập nhật giá trị đó chỉ trong một nơi. Điều ít được thừa nhận là điều này cũng ngăn giá trị đó vô tình bị sửa đổi, bởi vì một thay đổi như vậy sẽ hiển thị ở mọi nơi. Vì vậy, vâng, "" ngắn hơn EMPTY, nhưng EMPTY an toàn hơn khi sử dụng so với "".

Vì vậy, quay trở lại câu hỏi ban đầu, chúng ta chỉ có thể suy đoán rằng các nhà thiết kế ngôn ngữ có thể không nhận thức được lợi ích này của việc cung cấp các hằng số cho các giá trị theo nghĩa đen thường được sử dụng. Hy vọng rằng, một ngày nào đó chúng ta sẽ thấy các hằng chuỗi được thêm vào trong Java.


-16

Đối với những người yêu cầu ""String.Emptycó thể hoán đổi cho nhau hoặc điều đó ""tốt hơn, bạn rất sai.

Mỗi lần bạn làm một cái gì đó như myVariable = ""; bạn đang tạo một thể hiện của một đối tượng. Nếu đối tượng String của Java có hằng số công khai EMPTY, sẽ chỉ có 1 thể hiện của đối tượng ""

Ví dụ: -

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 bao gồm String.EMPTY) Con trỏ tới 1 đối tượng

Hoặc là: -

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

10 con trỏ đến 10 đối tượng

Điều này là không hiệu quả và trong suốt một ứng dụng lớn, có thể là đáng kể.

Có lẽ trình biên dịch Java hoặc thời gian chạy đủ hiệu quả để tự động trỏ tất cả các cá thể của "" vào cùng một thể hiện, nhưng nó có thể không và cần xử lý bổ sung để đưa ra quyết định đó.


9
Sai, theo stackoverflow.com/questions/1881922/ , chuỗi "" sẽ được sử dụng lại từ chuỗi String.
RealHowTo

1
Tôi đã nói rằng nó có thể sử dụng lại cùng một đối tượng và nếu vậy, vẫn kém hiệu quả hơn, bởi vì nó cần tìm đối tượng đó (trong nhóm chuỗi), vậy tôi đã nhầm như thế nào? Bất kể, có một số lý do tại sao String.Empty vượt trội hơn, bao gồm ngăn ngừa các lỗi như myVar = ""; và khả năng đọc cũng như cải thiện hiệu suất tôi đã nêu. Đó là một thực hành tốt để sử dụng hằng số thay vì tạo chuỗi ký tự, nếu không vì lý do nào khác; nó dễ dàng hơn để duy trì mã.
Gian hàng Antony

1
Tôi nghi ngờ rằng đối số hiệu suất của bạn là hợp lệ vì JLS nói rằng hằng số sẽ được coi là nghĩa đen tại thời gian biên dịch ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ). Khả năng đọc là một đối số tốt hơn.
RealHowTo

3
@AntonySmith - Tôi đoán bạn cần nghiên cứu Java thêm một chút hoặc có lẽ bạn biết lỗi của mình bây giờ. Các chuỗi Java là bất biến và trong một nhóm. Vì vậy, chỉ có một đối tượng Chuỗi cho "" trong JVM, bất kể nó được tìm thấy bao nhiêu lần trong mã. Bạn có thể kiểm tra xem một chuỗi có trống không bằng cách thực hiệnif (text == "")
Ajoy Bhatia

2
Sai lầm. Bình luận này nên được xóa.
Elad Tabak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.