object == null hay null == object?


96

Tôi đã nghe ai đó nói rằng null == objecttốt hơn là object == null kiểm tra

ví dụ :

void m1(Object obj ) {
   if(null == obj)  // Is this better than object == null ? Why ?
       return ;
   // Else blah blah
}

Có lý do nào không hay đây là một huyền thoại khác? Cảm ơn vì sự giúp đỡ.


Dupe của 271561 và 1957836 (ngoại trừ cái này ghi là 'bằng Java')
Gishu

20
Java khác với C #
Jijoy

5
Nếu có một lợi thế đáng kể hiệu suất, sau đó chắc chắn trình biên dịch sẽ tối ưu hóa nó ...
Andreas Dolk

Đối với các nulltham chiếu, hành động mặc định phải là ném một NPE. Một số thư viện đẹp (chẳng hạn như thư viện Java JDK7) có một phương thức giống như vậy public static <T> T notNull(T obj) { if (obj == null) { throw new NullPointerException(); } else { return obj; } }. Cũng có @NonNull(hoặc @Nonnull?), Nhưng bị "xóa".
Tom Hawtin - tackline

Câu trả lời:


140

Đây có lẽ là một thói quen học được từ C, để tránh loại lỗi đánh máy này (đơn =thay vì kép ==):

if (object = null) {

Quy ước đặt hằng số ở bên trái ==không thực sự hữu ích trong Java vì Java yêu cầu biểu thức trong một ifđánh giá thành một booleangiá trị, vì vậy trừ khi hằng số là a boolean, bạn sẽ gặp lỗi biên dịch theo cách bạn đặt tranh luận. (và nếu nó là boolean, bạn vẫn không nên sử dụng ==...)


4
mà isnt một thói quen rất hữu ích cho java, kể từ khi typo sẽ cho kết quả trong một lỗi biên dịch trên java
radai


3
@Chandru cho một Boolean, bạn có thể sử dụng x.booleanValue()hoặc !x.booleanValue(). x == truehoặc x == falsetrong tình trạng biểu hiện là có mùi hôi, IMHO.
Laurence Gonsalves

2
Anh ta đang kiểm tra null ở đây. Và có những trường hợp anh ta thực sự phải kiểm tra một Boolean cho null vì null không đúng cũng không sai.
Chandra Sekar

1
Có thói quen sử dụng null == objectchỉ để đảm bảo rằng chúng ta không vô tình ghi đè đối tượng bằng lỗi đánh máy hoàn toàn không phải là một công dụng. Điều đó có nghĩa là, chúng tôi đang tự đào tạo rằng bây giờ tôi sử dụng "null" trước, nó không sao cả, ngay cả khi tôi mắc lỗi. Điều đó không có nghĩa là mã hoạt động như mong đợi. Ngay cả khi null = objectđược đưa ra ở vị trí của null == object, chương trình sẽ không hoạt động như mong đợi! Vậy thì chẳng ích gì khi tuân theo quy ước này!
VanagaS

32

Như những người khác đã nói, đó là một thói quen học được từ C để tránh lỗi chính tả - mặc dù ngay cả trong C, tôi vẫn mong đợi các trình biên dịch tốt ở mức cảnh báo đủ cao để đưa ra cảnh báo. Như Chandru nói, so sánh với null trong Java theo cách này sẽ chỉ gây ra vấn đề nếu bạn đang sử dụng một biến kiểu Boolean(mà bạn không có trong mã mẫu). Tôi muốn nói rằng đó là một tình huống khá hiếm gặp và không phải là tình huống đáng để thay đổi cách bạn viết mã ở mọi nơi khác. (Tôi sẽ không bận tâm đến việc đảo ngược các toán hạng ngay cả trong trường hợp này; nếu tôi suy nghĩ đủ rõ ràng để xem xét đảo ngược chúng, tôi chắc chắn rằng tôi có thể đếm các dấu bằng.)

Điều chưa được đề cập là nhiều người (chắc chắn bao gồm cả tôi) thấy if (variable == constant)biểu mẫu này dễ đọc hơn - đó là một cách tự nhiên hơn để thể hiện bản thân. Đây là lý do để không sao chép một cách mù quáng một quy ước từ C. Bạn nên luôn đặt câu hỏi về thực tiễn (như bạn đang làm ở đây :) trước khi cho rằng những gì có thể hữu ích trong môi trường này lại hữu ích trong môi trường khác.


3
Tôi đồng ý với mọi lời bạn nói, đặc biệt là phần "sao chép một cách mù quáng một quy ước". Tôi đang đọc mã ngay bây giờ và kiểu đối tượng null = làm phiền tôi rất nhiều nên tôi đã tìm kiếm nó và đến đây. Các coder đã nghĩ gì?
Adrian M

28

Điều này không có nhiều giá trị trong Java (1.5+) ngoại trừ khi loại đối tượng là Boolean. Trong trường hợp đó, điều này vẫn có thể hữu ích.

if (object = null)sẽ không gây ra lỗi biên dịch trong Java 1.5+ nếu có đối tượng Booleannhưng sẽ ném NullPointerExceptionvào thời gian chạy.


Bạn có thể có nghĩa là nó sẽ gây ra thất bại biên soạn :)
VAVA

7
Không, nó sẽ không gây ra lỗi biên dịch khi đối tượng là Boolean.
Chandra Sekar

Không phải nó giống nhau cho mọi loại đối tượng ngoài Boolean?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
Đối với các kiểu không phải Boolean, mã sẽ không biên dịch vì kiểu của biểu thức "object = null" sẽ không phải là boolean. Do tính năng tự động đấm bốc, nó sẽ biên dịch cho Boolean.
Chandra Sekar

Nhưng tại sao hành vi này cho Boolean? Bất kỳ cơ sở lý luận?
Rohit Banga

9

Trong Java không có lý do chính đáng.

Một số câu trả lời khác cho rằng đó là do bạn có thể vô tình làm cho nó bị gán thay vì bình đẳng. Nhưng trong Java, bạn phải có boolean trong if, vì vậy điều này:

if (o = null)

sẽ không biên dịch.

Lần duy nhất điều này có thể quan trọng trong Java là nếu biến là boolean:

int m1(boolean x)
{
    if (x = true)  // oops, assignment instead of equality

4
Nhưng tại sao bạn sẽ viết == truehoặc tương tự == true == true.
Tom Hawtin - tackline

7
Không có lý do chính đáng để viết == true. Nhưng tôi đã chứng kiến ​​quá nhiều mã xấu trong sự nghiệp của mình đến nỗi tôi không còn hỏi tại sao ai đó sẽ viết một cái gì đó và chỉ chấp nhận rằng một số người đã viết mã không cần thiết / có vấn đề.
R Samuel Klatchko

1
Thật vậy, có rất nhiều mã kém đang bay xung quanh, tuy nhiên, khi được coi x == truelà xấu vì nó có thể bị viết nhầm thành x = true, sẽ không có nhiều ý nghĩa khi thay đổi nó thành true == xthay vì chỉ x.
Holger

9

Điều này cũng liên quan chặt chẽ đến:

if ("foo".equals(bar)) {

điều này thuận tiện nếu bạn không muốn đối phó với NPE:

if (bar!=null && bar.equals("foo")) {

có thể được thuận tiện nhưng có thể nguy hiểm blue-walrus.com/2010/11/...
Oliver Watkins

@OliverWatkins: Tôi thấy bài viết này yếu. Giả sử biến có kiểu int. Nếu không được khởi tạo, giá trị sẽ là 0 và lời hứa của bài viết sẽ không được giữ nguyên. Thực tế rằng Chuỗi là đối tượng và int là nguyên thủy không liên quan đến thực tế là một lập trình viên có thể quên init một biến. Trong câu hỏi này, chúng tôi chỉ giải quyết vấn đề so sánh chuỗi null.
cherouvim

@cherouvim thực tế intlà một loại nguyên thủy có liên quan, vì không thể gọi equalstrên một int, do đó, không có ích gì khi thảo luận về wether để sử dụng x.equals(constant)hoặc constant.equals(x)cho intcác giá trị. Và đối với Integercác giá trị, giá trị mặc định là nullhơn 0.
Holger

5

Thủ thuật này được cho là để ngăn chặn các v = nullloại lỗi chính tả.

Nhưng Java chỉ cho phép các biểu thức boolean làm if()điều kiện để thủ thuật đó không có nhiều ý nghĩa, trình biên dịch sẽ tìm ra những lỗi chính tả đó.

Tuy nhiên, nó vẫn là thủ thuật có giá trị đối với mã C / C ++.


3

Vì lý do tương tự, bạn làm điều đó trong C; phép gán là một biểu thức, vì vậy bạn đặt chữ ở bên trái để bạn không thể ghi đè nó nếu bạn vô tình sử dụng =thay thế ==.


Đó chỉ là một vấn đề trong Java đối với các kiểu boolean, phải không? Bất kỳ kiểu gán nào khác sẽ không có kiểu boolean và sẽ gây ra lỗi trình biên dịch.
Scott Smith

1
nope, trình biên dịch Java sẽ bắt rằng loại typo bất cứ điều gì theo thứ tự bạn thích
VAVA

@Jijoy - Tôi không nghĩ điều này có liên quan gì đến hiệu suất. Điều này nghe có vẻ giống như một mẹo cũ trong C để tránh sai lầm đáng sợ về phép gán-trong-một-điều kiện-biểu thức. Ý tưởng là nếu bạn đang cố gắng kiểm tra xem có xbằng không 5, khi bạn nhập nhầm if (x = 5), nó sẽ biên dịch một cách lặng lẽ (và luôn đánh giá thành true, bất kể giá trị của x). Tuy nhiên, nếu bạn có thói quen luôn chỉ định nghĩa đen trước: 'if (5 = x)', trình biên dịch có thể kiểm tra lại công việc của bạn và giúp bạn tiết kiệm thời gian sử dụng trình gỡ lỗi. Các trình biên dịch hiện đại làm cho thói quen này trở nên không cần thiết.
Scott Smith

6
-1: Nếu bạn vô tình sử dụng = nó sẽ không biên dịch trong Java; vì vậy lý do từ C không áp dụng.
Jon Skeet

Về mặt kỹ thuật nếu objthuộc loại java.lang.Boolean( loại B lớn), thì nó có thể tạo ra sự khác biệt (tôi nghĩ, không thực sự thử hay bất cứ điều gì).
Tom Hawtin - tackline

3

Đó là đối với những người thích có hằng số ở bên trái. Trong hầu hết các trường hợp, việc có hằng số ở bên trái sẽ ngăn NullPointerException được ném (hoặc có một lần kiểm tra giá trị khác). Ví dụ, phương thức String bằng cũng kiểm tra null. Có hằng số ở bên trái, sẽ giúp bạn không phải viết séc bổ sung. Mà, theo một cách khác cũng được thực hiện sau đó. Có giá trị null ở bên trái chỉ là nhất quán.

giống:

 String b = null;
 "constant".equals(b);  // result to false
 b.equals("constant");  // NullPointerException
 b != null && b.equals("constant");  // result to false

ẩn này của NPE chỉ tạo ra thậm chí khó khăn hơn để tìm lỗi tiếp tục hạ
Oliver Watkins

2

Đó là điều kiện Yoda viết theo cách khác

Trong java

String myString = null;
if (myString.equals("foobar")) { /* ... */ } //Will give u null pointer

tình trạng yoda

String myString = null;
if ("foobar".equals(myString)) { /* ... */ } // will be false 

1

So sánh với đoạn mã sau:

    String pingResult = "asd";
    long s = System.nanoTime ( );
    if ( null != pingResult )
    {
        System.out.println ( "null != pingResult" );
    }
    long e = System.nanoTime ( );
    System.out.println ( e - s );

    long s1 = System.nanoTime ( );
    if ( pingResult != null )
    {
        System.out.println ( "pingResult != null" );
    }
    long e1 = System.nanoTime ( );
    System.out.println ( e1 - s1 );

Đầu ra (Sau nhiều lần thực hiện):

null != pingResult
325737
pingResult != null
47027

Do đó, pingResult != nulllà người chiến thắng.


7
Chạy thử nghiệm của bạn trong một vòng lặp bổ sung! Hoặc chỉ chuyển đổi các câu lệnh IF. Truyện dài ngắn: không có sự khác biệt! Vòng lặp đầu tiên luôn chậm hơn.
Marcel Jaeschke

Trong thử nghiệm này, pingResult luôn không null. Điều gì xảy ra với thời gian của pingResult là null? Tôi cá rằng nó độc lập với nền tảng, nhưng trên ngăn xếp Oracle Java 1.6 / Linux của tôi, kết quả khá đồng đều (trong một vòng lặp), ngoại trừ nếu pingResult là null, thì cả hai lần kiểm tra đều nhanh hơn vài phần trăm.
Thi thiên 33 của yêu tinh

1
nếu bạn đặt "pingResult! = null block trước null! = pingResult block, nó sẽ dẫn đến kết quả giống như" pingResult! = null 325737 "
Sola Yang

Như @Sola Yang nói, nếu bạn đặt pingResult! = Null trước đó, bạn sẽ thấy rằng nó mất nhiều thời gian hơn null! = PingResult. Nếu pingResult! = Null nhanh hơn null! = PingResult IDE (như IntelliG, Eclipse, ...) sẽ đưa ra cảnh báo để buộc các nhà phát triển sử dụng vai trò này;)
adil.hilmi

1

Do tính chất giao hoán của nó , sự khác biệt duy nhất giữa object == nullnull == object( phiên bản Yoda ) là về bản chất nhận thức : cách mã được đọc và tiêu hóa bởi người đọc. Tuy nhiên, tôi không biết câu trả lời chính xác, nhưng tôi biết cá nhân tôi thích so sánh đối tượng tôi đang kiểm tra với một thứ khác hơn là so sánh một thứ khác với đối tượng tôi đang kiểm tra , nếu điều đó có ý nghĩa. Bắt đầu với chủ đề, sau đó là giá trị để so sánh với nó.

Trong một số ngôn ngữ khác, kiểu so sánh này hữu ích hơn.

Mặc dù vậy, để bảo vệ an toàn khỏi dấu "=" bị thiếu, tôi nghĩ viết null == object là một hành động sai lầm trong lập trình phòng thủ . Cách tốt hơn đối với mã cụ thể này là đảm bảo hành vi bằng kiểm tra junit. Hãy nhớ rằng, lỗi có thể xảy ra khi thiếu dấu "=" không phụ thuộc vào các đối số đầu vào của phương thức - bạn không phụ thuộc vào việc người khác sử dụng đúng API này - vì vậy thay vào đó, kiểm tra junit là hoàn hảo để bảo vệ an toàn chống lại điều đó. Dù sao, bạn sẽ muốn viết các bài kiểm tra junit để xác minh hành vi; thiếu "=" đương nhiên nằm trong phạm vi.

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.