objeto == nulo ou nulo == objeto?

96

Eu ouvi de alguém que null == objecté melhor do que object == null verificar

por exemplo :

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

Existe alguma razão ou este é outro mito? Obrigado pela ajuda.

Jijoy
fonte
Dupe de 271561 e 1957836 (exceto que este diz "em Java")
Gishu,
20
Java é diferente de C #
Jijoy,
5
Se houver foi uma vantagem significativa de desempenho, então com certeza o compilador otimizá-lo ...
Andreas Dolk
Para nullreferências, o curso de ação padrão deve ser lançar um NPE. Algumas bibliotecas interessantes (como a biblioteca Java JDK7) têm um método semelhante public static <T> T notNull(T obj) { if (obj == null) { throw new NullPointerException(); } else { return obj; } }. Há também @NonNull(ou @Nonnull?), Mas isso é "apagado".
Tom Hawtin - tackline
2
null == objecté conhecido como uma condição Yoda .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

140

Este é provavelmente um hábito aprendido com C, para evitar este tipo de erro de digitação (simples em =vez de duplo ==):

if (object = null) {

A convenção de colocar a constante no lado esquerdo de ==não é realmente útil em Java, pois Java requer que a expressão em um ifavalie um booleanvalor, então, a menos que a constante seja a boolean, você obteria um erro de compilação de qualquer maneira que colocasse o argumentos. (e se for um booleano, você não deveria usar de ==qualquer maneira ...)

Laurence Gonsalves
fonte
4
que não é um hábito muito útil para java, uma vez que o erro de digitação resultaria em um erro de compilação em java
radai
11
Exceto em um caso específico de canto. stackoverflow.com/questions/2369226/null-check-in-java/…
Chandra Sekar,
3
@Chandru para um booleano, você pode usar x.booleanValue()ou !x.booleanValue(). x == trueou x == falseem uma expressão de condição é um cheiro ruim, IMHO.
Laurence Gonsalves,
2
Ele está procurando por null aqui. E há casos em que ele realmente precisa verificar se um booleano é nulo, pois nulo não é verdadeiro nem falso.
Chandra Sekar
1
Habituar-se a usar null == objectapenas para ter certeza de que não sobrescreveremos o objeto acidentalmente com um erro de digitação não deve ser um caso de uso. O que significa que estamos treinando para que agora que eu use "null" primeiro, tudo bem, mesmo que eu cometa um erro. Isso não significa que o código funcione conforme o esperado. Mesmo se null = objectfor dado no lugar de null == object, o programa não funcionará como esperado! Então não há sentido em seguir esta convenção!
VanagaS
32

Como outros já disseram, é um hábito aprendido com C para evitar erros de digitação - embora mesmo em C eu esperasse compiladores decentes em níveis de aviso altos o suficiente para dar um aviso. Como diz Chandru, comparar com null em Java dessa forma só causaria problemas se você estivesse usando uma variável do tipo Boolean(que não está no código de amostra). Eu diria que é uma situação muito rara, e não uma para a qual vale a pena mudar a maneira como você escreve o código em qualquer outro lugar. (Eu não me incomodaria em reverter os operandos, mesmo neste caso; se estou pensando com clareza o suficiente para considerar revertê-los, tenho certeza de que posso contar os sinais de igual).

O que não foi mencionado é que muitas pessoas (eu certamente incluído) acham o if (variable == constant)formulário mais legível - é uma forma mais natural de se expressar. Esta é uma razão para não copiar cegamente uma convenção de C. Você deve sempre questionar as práticas (como está fazendo aqui :) antes de presumir que o que pode ser útil em um ambiente é útil em outro.

Jon Skeet
fonte
3
Eu concordo com cada palavra que você disse, especialmente a parte "copie cegamente uma convenção". Estou lendo um código agora e o estilo null = object me irrita tanto que procurei e vim aqui. O que o codificador estava pensando?
Adrian M,
28

Isso não tem muito valor em Java (1.5+), exceto quando o tipo de objeto é Boolean. Nesse caso, isso ainda pode ser útil.

if (object = null)não causará falha de compilação em Java 1.5+ se o objeto for, Booleanmas lançaria um NullPointerExceptionem tempo de execução.

Chandra Sekar
fonte
Você provavelmente quis dizer que isso causaria falha de compilação :)
vava
7
Não, não causará um erro de compilação quando o objeto for booleano.
Chandra Sekar,
Não é o mesmo para todos os tipos de objeto além do booleano?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Para tipos não booleanos, o código não será compilado porque o tipo da expressão "object = null" não será booleano. Devido ao auto-boxing, ele irá compilar para Boolean.
Chandra Sekar
Mas por que esse comportamento para Boolean? Alguma justificativa?
Rohit Banga
9

Em Java, não há um bom motivo.

Algumas outras respostas afirmam que é porque você pode acidentalmente fazer atribuição em vez de igualdade. Mas em Java, você precisa ter um booleano em um if, então este:

if (o = null)

não vai compilar.

A única vez que isso pode importar em Java é se a variável for booleana:

int m1(boolean x)
{
    if (x = true)  // oops, assignment instead of equality
R Samuel Klatchko
fonte
4
Mas por que você escreveria == trueou igualmente == true == true.
Tom Hawtin - tackline
7
Não há um bom motivo para escrever == true. Mas eu vi tantos códigos ruins em minha carreira que não pergunto mais por que alguém escreveria algo e simplesmente aceito que algumas pessoas escreveram códigos desnecessários / questionáveis.
R Samuel Klatchko,
1
De fato, ainda há muito código ruim circulando por aí, quando considerado x == truecomo ruim porque poderia ser escrito por engano x = true, não faria muito sentido alterá-lo para em true == xvez de apenas x.
Holger
9

Isso também está intimamente relacionado a:

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

o que é conveniente se você não quiser lidar com NPEs:

if (bar!=null && bar.equals("foo")) {
Cherouvim
fonte
pode ser conveniente, mas pode ser perigoso. blue-walrus.com/2010/11/…
Oliver Watkins
@OliverWatkins: Acho este artigo fraco. Suponha que a variável fosse do tipo int. Se não inicializado, o valor seria 0 e a promessa do artigo não seria válida. O fato de que Strings são objetos e ints são primitivos é irrelevante do fato de que um programador pode se esquecer de iniciar uma variável. Nesta questão, simplesmente resolvemos a comparação de String nula.
Cherouvim
@cherouvim o fato de intser um tipo primitivo é relevante, pois é impossível invocar equalsem um int, portanto, não faz sentido discutir se usar x.equals(constant)ou constant.equals(x)para intvalores. E para Integervalores, o valor padrão é em nullvez de 0.
Holger
5

Este truque deveria evitar v = nulltipos de erros de digitação.

Mas o Java permite apenas expressões booleanas como if()condições, então esse truque não faz muito sentido, o compilador encontrará esses erros de digitação de qualquer maneira.

No entanto, ainda é um truque valioso para código C / C ++.

vava
fonte
3

Pelo mesmo motivo, você faz isso em C; atribuição é uma expressão, então você coloca o literal à esquerda para que não possa sobrescrevê-lo se acidentalmente usar em =vez de ==.

Ignacio Vazquez-Abrams
fonte
É apenas um problema em Java para tipos booleanos, certo? Qualquer outro tipo de atribuição não terá um tipo booleano e deve causar um erro do compilador.
Scott Smith,
1
não, o compilador Java detectará esse tipo de erro de digitação na ordem que você preferir
vava,
@Jijoy - Não acho que isso tenha nada a ver com desempenho. Isso soa como um velho truque em C para evitar o temido erro de atribuição dentro de uma expressão condicional. A ideia era que, se você estiver tentando verificar se xé igual 5, ao digitar por engano if (x = 5), ele compilará silenciosamente (e sempre avaliará como true, independentemente do valor de x). No entanto, se você adquirir o hábito de sempre especificar o literal primeiro: 'if (5 = x)', o compilador pode verificar novamente seu trabalho e poupar tempo batendo cabeça no depurador. Compiladores modernos tornam esse hábito desnecessário.
Scott Smith,
6
-1: Se você usar acidentalmente = ele não compilará em Java; portanto, o motivo de C não se aplica.
Jon Skeet,
Tecnicamente, se objfosse do tipo java.lang.Boolean(grande B), então poderia fazer a diferença (eu acho, não tentei realmente nem nada).
Tom Hawtin - tackline,
3

Isso é para pessoas que preferem ter a constante do lado esquerdo. Na maioria dos casos, ter a constante no lado esquerdo impedirá que NullPointerException seja lançado (ou ter outro nullcheck). Por exemplo, o método String equals também faz uma verificação de nulos. Ter a constante à esquerda impedirá que você faça o cheque adicional. Que, de outra forma, também é realizado posteriormente. Ter o valor nulo à esquerda é apenas ser consistente.

gostar:

 String b = null;
 "constant".equals(b);  // result to false
 b.equals("constant");  // NullPointerException
 b != null && b.equals("constant");  // result to false
SPee
fonte
esconder o NPE apenas torna ainda mais difícil encontrar bugs mais abaixo
Oliver Watkins
2

É a condição de Yoda, escrevendo de maneira diferente

Em java

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

condição yoda

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

Compare com o seguinte código:

    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 );

Resultado (após várias execuções):

null != pingResult
325737
pingResult != null
47027

Portanto, pingResult != nullé o vencedor.

Avinash
fonte
7
Execute seu teste em um loop adicional! Ou apenas mude as instruções IF. Resumindo: não há diferença! O primeiro loop é sempre mais lento.
Marcel Jaeschke
Neste teste, pingResult é sempre não nulo. O que acontece com o tempo de pingResult é nulo? Aposto que é independente de plataforma, mas na minha pilha Oracle Java 1.6 / Linux, os resultados são praticamente uniformes (em um loop), exceto se pingResult for nulo, ambas as verificações são alguns por cento mais rápidas.
Ogre Salmo 33
1
se você colocar "pingResult! = bloco nulo antes de nulo! = bloco pingResult, o resultado será algo como" pingResult! = nulo 325737 "
Sola Yang
Como @Sola Yang diz, se você colocar pingResult! = Null antes, verá que leva mais tempo do que null! = PingResult. Se pingResult! = Null for mais rápido que null! = PingResult o IDE (como IntelliG, Eclipse, ...) fará um aviso para forçar os desenvolvedores a usarem esta função;)
adil.hilmi
1

Por causa de sua propriedade comutativa , a única diferença entre object == nulle null == object(a versão Yoda ) é de natureza cognitiva : como o código é lido e digerido pelo leitor. Não sei a resposta definitiva, mas sei que pessoalmente prefiro comparar o objeto que estou inspecionando a outra coisa, em vez de comparar outra coisa ao objeto que estou inspecionando , se isso fizer algum sentido. Comece com o assunto e, em seguida, o valor com o qual compará-lo.

Em alguns outros idiomas, esse estilo de comparação é mais útil.

Para se proteger contra a falta de um sinal "=" em geral, porém, acho que escrever null == objecté um ato equivocado de programação defensiva . A melhor maneira de contornar esse código específico é garantir o comportamento com um teste junit. Lembre-se, o possível erro de perder um "=" não depende dos argumentos de entrada do método - você não depende do uso correto desta API por outras pessoas - então, um teste junit é perfeito para proteger contra isso. De qualquer forma, você desejará escrever testes junit para verificar o comportamento; um "=" ausente naturalmente está dentro do escopo.

Benny Bottema
fonte