Evite! = Nulo

Eu uso o object != null para evitar um NullPointerException .

Existe uma boa alternativa para isso?

Por exemplo:

 if (someobject != null) { someobject.doCalc(); } 

Isso evita um NullPointerException quando não se sabe se o objeto é null ou não.

Por favor, note que a resposta aceita pode estar desatualizada, veja levitrasi.net.site/questions/50 / ... para uma abordagem posterior.

3608
07 нояб. definido por Goran Martinic 07 de novembro 2008-11-07 11:31 '08 at 11:31 am 2008-11-07 11:31
@ 60 respostas
  • 1
  • 2

Parece-me um problema bastante comum que os desenvolvedores mais jovens tendem a encontrar em algum momento: eles não sabem ou não confiam nos contratos em que participam e os superestimam defensivamente quanto a zeros. Além disso, ao escrever seu próprio código, eles tendem a confiar em retornar zeros para indicar algo que requer que o chamador verifique zeros.

Em outras palavras, há dois casos quando ocorre uma verificação de zero:

  • Onde null é uma resposta válida em termos de um contrato; e

  • Se esta for uma resposta inválida.

(2) fácil. Use assert (assertions) ou fail (por exemplo, NullPointerException ). As asserções são uma função Java muito pouco usada, adicionada em 1.4. Sintaxe:

 assert <condition> 

ou

 assert <condition> : <object> 

onde <condition> é uma expressão lógica e <object> é um objeto, a saída do toString() será incluída no erro.

A assert chama Error ( AssertionError ) se a condição não for verdadeira. Por padrão, o Java ignora as asserções. Você pode ativar asserções passando a opção -ea para a JVM. Você pode ativar e desativar asserções para classes e pacotes individuais. Isso significa que você pode testar o código com asserções no desenvolvimento e no teste e desativá-las em um ambiente de produção, embora meus testes tenham sido exibidos ao lado da falta de impacto no desempenho das asserções.

Não use asserções neste caso, OK, porque o código irá falhar, o que acontecerá se você usar asserções. A única diferença é que, com as declarações, isso pode acontecer mais cedo, de uma maneira mais significativa e, possivelmente, com informações adicionais que podem ajudá-lo a entender por que isso aconteceu, se você não esperava.

(1) é um pouco mais complicado. Se você não tem controle sobre o código que está chamando, você está preso. Se null é uma resposta válida, você deve verificar isso.

Se este é um código que você controla, no entanto (e isso geralmente acontece), então esta é outra história. Evite usar zeros como resposta. É fácil usar métodos que retornam coleções: retornar coleções vazias (ou matrizes) em vez de zeros quase o tempo todo.

Com não-coleções, isso pode ser complicado. Considere isso como um exemplo: se você tiver essas interfaces:

 public interface Action { void doSomething(); } public interface Parser { Action findAction(String userInput); } 

onde o Parser usa a entrada bruta do usuário e encontra algo para fazer, talvez se você implementar de alguma forma a interface de linha de comando. Agora você pode fazer um contrato que retorna null se não houver nenhuma ação correspondente. Isso leva à verificação zero de que você está falando.

Uma solução alternativa é nunca retornar null e usar o modelo Null Object em vez disso:

 public class MyParser implements Parser { private static Action DO_NOTHING = new Action() { public void doSomething() {  } }; public Action findAction(String userInput) { // ... if (  ) { return DO_NOTHING; } } } 

Para comparação:

 Parser parser = ParserFactory.getParser(); if (parser == null) { // now what? // this would be an example of where null isn't (or shouldn't be) a valid response } Action action = parser.findAction(someInput); if (action == null) { // do nothing } else { action.doSomething(); } 

para

 ParserFactory.getParser().findAction(someInput).doSomething(); 

o que é muito melhor porque resulta em código mais compactado.

No entanto, pode ser absolutamente necessário que o método findAction () lance uma exceção com uma mensagem de erro significativa - especialmente neste caso quando você depende da entrada do usuário. Seria muito melhor se o método findAction escolhesse uma exceção do que para o método de chamada, a fim de explodir uma NullPointerException simples sem explicação.

 try { ParserFactory.getParser().findAction(someInput).doSomething(); } catch(ActionNotFoundException anfe) { userConsole.err(anfe.getMessage()); } 

Ou, se você acha que o mecanismo try / catch é muito feio e não faz nada, sua ação padrão deve fornecer feedback do usuário.

 public Action findAction(final String userInput) {  return new Action() { public void doSomething() { userConsole.err("Action not found: " + userInput); } } } 
2422
07 нояб. A resposta é dada cletus 07 de novembro 2008-11-07 15:06 '08 às 15:06 2008-11-07 15:06

Se você usa (ou planeja usar) um IDE Java, como JetBrains IntelliJ IDEA , Eclipse ou Netbeans, ou uma ferramenta como findbugs, é possível usar anotações para resolver esse problema.

Basicamente, você tem @Nullable e @NotNull .

Você pode usar no método e nos parâmetros, por exemplo:

 @NotNull public static String helloWorld() { return "Hello World"; } 

ou

 @Nullable public static String helloWorld() { return "Hello World"; } 

O segundo exemplo não será compilado (no IntelliJ IDEA).

Quando você usa a primeira função helloWorld() em outro trecho de código:

 public static void main(String[] args) { String result = helloWorld(); if(result != null) { System.out.println(result); } } 

Agora, o compilador IntelliJ IDEA informará que a verificação é inútil, já que a função helloWorld() não retornará null .

Use o parâmetro

 void someMethod(@NotNull someParameter) { } 
border=0

se você escrever algo como:

 someMethod(null); 

Isso não irá compilar.

Último exemplo usando @Nullable

 @Nullable iWantToDestroyEverything() { return null; } 

Fazendo isso

 iWantToDestroyEverything().something(); 

E você pode ter certeza de que isso não vai acontecer. :)

Essa é uma boa maneira de permitir que o compilador verifique algo mais que o normal e fortaleça seus contratos. Infelizmente, não é suportado por todos os compiladores.

No IntelliJ IDEA 10.5 e posterior, eles adicionaram suporte a qualquer outra implementação @Nullable @NotNull .

Veja a entrada do blog. Mais flexíveis e personalizáveis ​​@ Anotações Nullable / @ NotNull .

528
05 марта '10 в 13:31 2010-03-05 13:31 Resposta foi dada por Luca Molteni em 05 de março de 2010 às 13:31 2010-03-05 13:31

Se valores nulos não são permitidos

Se o seu método é chamado externamente, comece com algo como isto:

 public void method(Object object) { if (object == null) { throw new IllegalArgumentException("..."); } 

Então, no restante deste método, você descobrirá que o object não object nulo.

Se este é um método interno (não faz parte da API), simplesmente documente que não pode ser nulo, e que é.

Exemplo:

 public String getFirst3Chars(String text) { return text.subString(0, 3); } 

No entanto, se o seu método simplesmente passar o valor e o próximo método passar, etc., isso pode se tornar problemático. Neste caso, você pode verificar o argumento como acima.

Se nulo for permitido

Isso realmente depende. Se você acha que eu costumo fazer algo assim:

 if (object == null) { // something } else { // something else } 

Então eu procuro e faço duas coisas completamente diferentes. Não há trecho de código feio, porque eu realmente preciso fazer duas coisas diferentes dependendo dos dados. Por exemplo, devo trabalhar com entrada ou devo calcular um bom valor padrão?


Eu realmente raramente tenho que usar o idioma if (object != null ... ).

Pode ser mais fácil dar exemplos se você mostrar exemplos de onde costuma usar o idioma.

286
07 нояб. a resposta é dada por myplacedk 07 nov. 2008-11-07 12:27 '08 at 12:27 pm 2008-11-07 12:27

Uau, eu quase não quero adicionar outra resposta quando temos 57 maneiras diferentes de recomendar o NullObject pattern , mas acho que algumas pessoas interessadas nesta questão gostariam de saber que há uma sugestão na tabela para o Java 7 adicionar " processamento com segurança nula " - uma sintaxe simplificada para a lógica if-not-equal-null.

O exemplo dado por Alex Miller é o seguinte:

 public String getPostcode(Person person) { return person?.getAddress()?.getPostcode(); } 

?. significa apenas cancelar o link para o identificador esquerdo, se não for nulo, caso contrário, avalie o resto da expressão como null . Algumas pessoas, como Dick Wall e os eleitores da Devoxx , membro do Post, realmente adoram essa proposta, mas há oposição, alegando que ele encorajará um maior uso de null como um valor de controle.


Atualização: a oferta oficial para o operador zero no Java 7 foi enviada para o Project Coin. A sintaxe é um pouco diferente do exemplo acima, mas o mesmo conceito.


Atualize. A oferta com zero operador seguro não foi incluída na moeda do projeto. Assim, você não verá essa sintaxe no Java 7.

216
17 янв. a resposta é dada por erickson 17 de janeiro 2009-01-17 08:08 '09 at 8:08 am 2009-01-17 08:08

Se valores indefinidos não são permitidos:

Você pode configurar seu IDE para alertá-lo sobre o potencial de cancelamento de zero. Por exemplo, no Eclipse, consulte Configurações> Java> Compilador> Erros / Avisos / Análise Zero.

Se valores indefinidos são permitidos:

Se você quiser definir uma nova API em que os valores indefinidos fazem sentido, use o modelo Opção (pode estar familiarizado com idiomas funcionais). Tem as seguintes vantagens:

  • A API indica explicitamente se uma entrada ou saída existe ou não.
  • O compilador força você a lidar com o caso "indefinido".
  • A variante é uma mônada , portanto, não há necessidade de verificar zeros válidos, apenas use map / foreach / getOrElse ou um combinador semelhante para usar com segurança o valor (exemplo) .

O Java 8 possui uma classe interna Optional (recomendada); para versões anteriores, há alternativas de biblioteca, por exemplo, Optional Guava Option ou FunctionalJava . Mas, como muitos modelos funcionais, o uso de Option em Java (até mesmo 8) resulta em um padrão que você pode reduzir usando uma linguagem de JVM menos detalhada, como Scala ou Xtend.

Se você precisa lidar com uma API que pode retornar valores NULL, não é possível fazer muito em Java. A Xtend e a Groovy possuem um operador Elvis ?: E um operador de cancelamento de referência nulo ?. mas note que isso retorna null no caso de uma referência nula, então simplesmente "cancela" o tratamento correto do valor nulo.

178
14 янв. A resposta é dada a partir de 14 de janeiro 2010-01-14 16:45 '10 às 16:45 2010-01-14 16:45

Apenas para esta situação -

Não verifique se a variável é nula antes de chamar o método equals (um exemplo de comparação de string abaixo):

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

resultará em um NullPointerException se foo não existir.

Você pode evitar isso comparando sua String seguinte maneira:

 if ( "bar".equals(foo) ) { // ... } 
163
09 нояб. a resposta é dada echox 09 de novembro 2008-11-09 15:24 '08 às 15:24 2008-11-09 15:24

No Java 8, uma nova classe java.util.Optional , que, talvez, solucione alguns problemas. Pode-se até dizer que isso melhora a legibilidade do código e, no caso de APIs públicas, simplifica o trabalho da interface da API com o cliente desenvolvedor.

Eles funcionam assim:

Um objeto opcional para este tipo ( Fruit ) é criado como o tipo de retorno do método. Pode estar vazio ou conter um objeto Fruit :

 public static Optional<Fruit> find(String name, List<Fruit> fruits) { for (Fruit fruit : fruits) { if (fruit.getName().equals(name)) { return Optional.of(fruit); } } return Optional.empty(); } 

Agora olhe para este código, onde estamos procurando a lista de fruits ( fruits ) para esta instância de frutas:

 Optional<Fruit> found = find("lemon", fruits); if (found.isPresent()) { Fruit fruit = found.get(); String name = fruit.getName(); } 

Você pode usar o operador map() para realizar um cálculo - ou recuperar um valor de um objeto opcional. orElse() permite que você forneça um backup para valores ausentes.

 String nameOrNull = find("lemon", fruits) .map(f -> f.getName()) .orElse("empty-name"); 

Naturalmente, uma verificação nula / vazia ainda é necessária, mas pelo menos o desenvolvedor está ciente de que o valor pode estar vazio e o risco de esquecer de verificar é limitado.

Em uma API construída do zero usando Optional , quando o valor de retorno pode estar vazio e retorna um objeto simples somente se não puder ser null (uma convenção), o código do cliente pode recusar verificações nulas nos valores dos objetos retornados ...

Naturalmente, Optional também pode ser usado como um argumento de método, talvez uma maneira melhor de especificar argumentos opcionais do que 5 ou 10 métodos de sobrecarga em alguns casos.

Optional oferece outros métodos convenientes, como orElse , que permitem usar o valor padrão e ifPresent , que funciona com expressões lambda .

Convido você a ler este artigo (minha principal fonte para escrever a resposta), na qual o problema NullPointerException (e geralmente um ponteiro nulo), bem como a solução (parcial) trazida por Optional , são bem explicados: Objetos Java adicionais .

137
25 апр. Resposta dada a Pierre Henry em 25 de abr 2013-04-25 18:22 13 às 18:22 2013-04-25 18:22

Dependendo de quais objetos você verifica, você pode usar algumas das classes em frações gerais do apache, por exemplo: coleções de coleções apache commons > e apache

Exemplo:

 String foo; ... if( StringUtils.isBlank( foo ) ) { ///do something } 

ou (dependendo do que você precisa verificar):

 String foo; ... if( StringUtils.isEmpty( foo ) ) { ///do something } 

A classe StringUtils é apenas uma das muitas; Existem algumas boas classes nas áreas comuns que fazem manipulação zero segura.

Abaixo está um exemplo de como você pode usar a validação nula em JAVA quando você ativa a biblioteca do apache (commons->

 public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) { Validate.notNull(validationEventHandler,"ValidationHandler not Injected"); return read(new StringReader(xml), true, validationEventHandler); } 

E se você usar o Spring, o Spring também terá a mesma funcionalidade em seu pacote, veja a biblioteca (spring -2.4.6.jar)

Um exemplo de uso dessa classe estática f de spring (org.springframework.util.Assert)

 Assert.notNull(validationEventHandler,"ValidationHandler not Injected"); 
113
07 нояб. resposta dada javamonkey79 07 nov. 2008-11-07 12:10 '08 às 12:10 2008-11-07 12:10
  • Se você acha que o objeto não deve ser nulo (ou é um erro), use assert.
  • Se o seu método não aceitar parâmetros nulos, diga isso no javadoc e use assert.

Você precisa verificar o objeto! = Nulo, somente se você quiser lidar com o caso quando o objeto pode estar vazio ...

Há uma sugestão para adicionar novas anotações ao Java7 para ajudar com os parâmetros null / notnull: http://tech.puredanger.com/java7/#jsr308

87
07 нояб. a resposta é dada pgras 07 de novembro 2008-11-07 11:55 '08 às 11:55 2008-11-07 11:55

Sou fã do código "fail fast". Pergunte a si mesmo: você está fazendo algo útil quando o parâmetro é zero? Se você não tem uma resposta clara para o que seu código deve fazer neste caso ... Ou seja, ele nunca deve ser zero e, em seguida, ignorá-lo e deixar lançar um NullPointerException. O código do chamador terá o mesmo valor NPE que a exceção IllegalArgumentException, mas será mais fácil para o desenvolvedor depurar e entender o que deu errado se o NPE for lançado, e não seu código tentando executar outras contingências imprevistas da lógica, o que acaba resultando para o fato de que o aplicativo ainda não funciona.

81
23 мая '11 в 21:18 2011-05-23 21:18 resposta foi dada por Alex Worden em 23 de maio '11 às 21:18 2011-05-23 21:18

Às vezes você tem métodos que funcionam com seus parâmetros, que definem uma operação simétrica:

 af(b); <-> bf(a); 

Se você sabe que b nunca pode ser zero, você pode simplesmente mudá-lo. É mais útil para iguais: em vez de foo.equals("bar"); melhor fazer "bar".equals(foo); .

69
07 нояб. Resposta dada Johannes Schaub - litb 07 nov 2008-11-07 12:04 '08 às 12:04 2008-11-07 12:04

A estrutura de coleções do Google oferece uma maneira agradável e elegante de obter validação zero.

A classe da biblioteca tem um método:

 static <T> T checkNotNull(T e) { if (e == null) { throw new NullPointerException(); } return e; } 

E usado (com import static ):

 ... void foo(int a, Person p) { if (checkNotNull(p).getAge() > a) { ... } else { ... } } ... 

Ou no seu exemplo:

 checkNotNull(someobject).doCalc(); 
69
29 дек. resposta dada por user2427 em 29 dez. 2008-12-29 16:50 '09 às 16:50 2008-12-29 16:50

Em vez de um padrão de objeto zero que tem seus usos, você pode considerar situações em que um objeto zero é um erro.

Quando uma exceção é lançada, observe o rastreio da pilha e cometa um erro.

67
07 нояб. Jim Nelson respondeu 07 de novembro 2008-11-07 11:50 '08 às 11:50 2008-11-07 11:50

O Java 7 tem uma nova classe de utilitário java.util.Objects na qual o método requireNonNull() . Tudo isso faz um throw NullPointerException se seu argumento é nulo, mas apaga o código um pouco. Exemplo:

 Objects.requireNonNull(someObject); someObject.doCalc(); 

O método é mais útil para verificar antes da atribuição no construtor, onde cada um de seus usos pode salvar três linhas de código:

 Parent(Child child) { if (child == null) { throw new NullPointerException("child"); } this.child = child; } 

torna-se

 Parent(Child child) { this.child = Objects.requireNonNull(child, "child"); } 
65
10 авг. Resposta dada por Stuart Marks 10 ago. 2012-08-10 10:08 '12 às 10:08 2012-08-10 10:08

Zero não é um problema. É parte integrante de um conjunto completo de ferramentas de modelagem. O software tem como objetivo simular a complexidade do mundo e zero carrega seu fardo. Nulo indica "Sem dados" ou "Desconhecido" em Java e afins. Portanto, para esses propósitos, é aconselhável usar valores nulos. Eu não prefiro o padrão "Zero Object"; Eu acho que ele levanta " quem vai guardar a questão dos guardiões ".
Se você me perguntar qual é o nome da minha namorada, direi que não tenho namorada. Em Java, retornarei null. Uma alternativa seria lançar uma exceção sensata para apontar algum problema que não pode ser (ou não deseja ser) resolvido ali mesmo e delegá-lo em algum lugar mais alto na pilha para repetir ou relatar um erro ao acessar os dados para o usuário.

  1. Para uma "questão desconhecida", dê uma "resposta desconhecida". (Não é seguro se estiver correto do ponto de vista comercial). Verificar os argumentos para null uma vez dentro de um método antes de usar libera vários chamadores de verificá-los antes de chamar.

     public Photo getPhotoOfThePerson(Person person) { if (person == null) return null; // Grabbing some resources or intensive calculation // using person object anyhow. } 

    O anterior leva a um fluxo lógico normal, a fim de obter uma foto de uma namorada inexistente da minha biblioteca de fotos.

     getPhotoOfThePerson(me.getGirlfriend()) 

    E isso corresponde à nova API Java (olhando para frente).

     getPhotoByName(me.getGirlfriend()?.getName()) 

    Embora um "fluxo normal de negócios" não permita que você encontre uma foto armazenada em um banco de dados para uma pessoa, usei um par, como mostrado abaixo, para alguns outros casos.

     public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException public static MyEnum parseMyEnumOrNull(String value); 

    E você não deve odiar digitar <alt> + <shift> + <j> (gerar javadoc no Eclipse) e escrever três palavras adicionais para a API pública. Isso será mais do que suficiente para todos, exceto para aqueles que não leem a documentação.

      

    ou

      
  2. Esse é um caso bastante teórico e, na maioria dos casos, você deve preferir a API segura nula de java (se lançada após outros 10 anos), mas NullPointerException é uma subclasse de Exception . Assim, é uma forma Throwable que indica as condições que um aplicativo razoável pode querer capturar ( javadoc )! Чтобы использовать первое преимущество привилегий и отдельный код обработки ошибок из "обычного" кода ( по словам создателей Java ), уместно, как и я, поймать NullPointerException .

     public Photo getGirlfriendPhoto() { try { return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName()); } catch (NullPointerException e) { return null; } }