new - tipos de exceções java




Evitando!=Instruções nulas (20)

Eu uso muito o object != null para evitar o 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.

Observe que a resposta aceita pode estar desatualizada, consulte https://stackoverflow.com/a/2386013/12943 para obter uma abordagem mais recente.


Se valores indefinidos não são permitidos:

Você pode configurar seu IDE para avisá-lo sobre o potencial de desreferência nula. Por exemplo, no Eclipse, consulte Preferências> Java> Compilador> Erros / Avisos / Análise nula .

Se valores indefinidos são permitidos:

Se você quiser definir uma nova API em que os valores indefinidos fazem sentido , use o Padrão de opções (pode ser familiar a partir de idiomas funcionais). Tem as seguintes vantagens:

  • É declarado explicitamente na API se existe uma entrada ou saída ou não.
  • O compilador força você a lidar com o caso "indefinido".
  • A opção é uma mônada , portanto, não há necessidade de verificação detalhada de nulos, apenas use map / foreach / getOrElse ou um combinador semelhante para usar com segurança o valor (example) .

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

Se você tiver que lidar com uma API que possa retornar valores nulos , não será possível fazer muito em Java. Xtend e Groovy possuem o operador Elvis ?: e o operador de referência do nulo seguro ?. , mas observe que isso retorna null no caso de uma referência nula, portanto, apenas "adia" o tratamento adequado de null.


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 desse método, você saberá que o object não é nulo.

Se for um método interno (não faz parte de uma API), apenas documente que não pode ser nulo, e é isso.

Exemplo:

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

No entanto, se o seu método apenas passar o valor, e o próximo método o transmitir, etc., pode ficar problemático. Nesse caso, você pode querer verificar o argumento como acima.

Se nulo for permitido

Isso realmente depende. Se achar que muitas vezes eu faço algo assim:

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

Então eu me ramifico 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 na entrada ou devo calcular um bom valor padrão?

Na verdade, é raro eu usar o idioma " if (object != null && ... ".

Pode ser mais fácil dar exemplos, se você mostrar exemplos de onde normalmente usa o idioma.


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

a.f(b); <-> b.f(a);

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


A estrutura de coleções do Google oferece uma maneira boa e elegante de atingir a verificação de nulos.

Existe um método em uma classe de biblioteca como esta:

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

E o uso é (com a import static ):

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

Ou no seu exemplo:

checkNotNull(someobject).doCalc();

Com o Java 8, vem a nova classe java.util.Optional que soluciona indiscutivelmente alguns dos problemas. Pode-se pelo menos dizer que melhora a legibilidade do código e, no caso de APIs públicas, torna o contrato da API mais claro para o desenvolvedor do cliente.

Eles funcionam assim:

Um objeto opcional para um determinado tipo ( Fruit ) é criado como o tipo de retorno de um 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 procuramos uma lista de Fruit ( fruits ) para uma dada instância de fruta:

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

Você pode usar o operador map() para executar um cálculo - ou extrair um valor de - um objeto opcional. orElse() permite fornecer um retorno para valores ausentes.

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

Naturalmente, a verificação do valor nulo / vazio ainda é necessária, mas pelo menos o desenvolvedor está consciente de que o valor pode estar vazio e o risco de esquecer de verificar é limitado.

Em uma API construída a partir do zero usando Optional sempre que um valor de retorno pode estar vazio e retornando um objeto simples somente quando não pode ser null (convenção), o código do cliente pode abandonar as verificações nulas em valores de retorno de objeto simples ...

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

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

Eu o convido a ler este artigo (minha principal fonte para escrever esta resposta), na qual a solução NullPointerException (e, em geral, ponteiro nulo), bem como a solução (parcial) trazida por Optional são bem explicadas: Objetos Opcionais Java .


Dependendo do tipo de objeto que você está verificando, você pode usar algumas das classes do apache commons, como: apache commons lang e apache commons collections

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 nos comuns que fazem manipulação segura nula.

Aqui segue um exemplo de como você pode usar a validação nula em JAVA quando você inclui a biblioteca do apache (commons-lang-2.4.jar)

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

E se você estiver usando o Spring, o Spring também tem a mesma funcionalidade em seu pacote, veja library (spring-2.4.6.jar)

Exemplo sobre como usar este classf estático da primavera (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

Eu sou fã do código "fail fast". Pergunte a si mesmo - você está fazendo algo útil no caso em que o parâmetro é nulo? Se você não tem uma resposta clara para o que seu código deve fazer nesse caso ... Ou seja, nunca deve ser nulo, em seguida, ignorá-lo e permitir que um NullPointerException seja lançado. O código de chamada fará tanto sentido quanto um NPE quanto seria um IllegalArgumentException, mas será mais fácil para o desenvolvedor depurar e entender o que deu errado se um NPE for lançado em vez de seu código tentar executar alguma outra contingência inesperada. lógica - que finalmente resulta na falha do aplicativo de qualquer maneira.


Isso para mim soa como um problema razoavelmente comum que desenvolvedores juniores a intermediários tendem a enfrentar em algum momento: eles não sabem ou não confiam nos contratos em que estão participando e sobrescrevem defensivamente para nulos. Além disso, ao escrever seu próprio código, eles tendem a confiar em retornar nulos para indicar algo, exigindo, assim, que o chamador verifique se há nulos.

Para colocar isso de outra maneira, há duas instâncias em que a verificação de nulos aparece:

  1. Onde null é uma resposta válida em termos do contrato; e

  2. Onde não é uma resposta válida.

(2) é fácil. Use instruções assert (afirmações) ou permita falha (por exemplo, NullPointerException ). As asserções são um recurso Java altamente subutilizado que foi adicionado em 1.4. A sintaxe é:

assert <condition>

ou

assert <condition> : <object>

onde <condition> é uma expressão booleana e <object> é um objeto cuja saída do método toString() será incluída no erro.

Uma instrução assert gera um Error ( AssertionError ) se a condição não for verdadeira. Por padrão, o Java ignora as asserções. Você pode ativar as 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 validar o código com as asserções durante o desenvolvimento e o teste e desativá-las em um ambiente de produção, embora meus testes tenham mostrado quase nenhum impacto no desempenho das asserções.

Não usar asserções neste caso é OK porque o código simplesmente falhará, que é o que acontecerá se você usar asserções. A única diferença é que, com as afirmações, isso pode acontecer mais cedo, de uma maneira mais significativa e possivelmente com informações extras, o que pode ajudá-lo a descobrir por que isso aconteceu se você não estivesse esperando por isso.

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

Se é o código que você controla, no entanto (e esse é frequentemente o caso), então é uma história diferente. Evite usar nulos como resposta. Com métodos que retornam coleções, é fácil: retornar coleções vazias (ou matrizes) em vez de nulos praticamente o tempo todo.

Com não-coleções, pode ser mais difícil. 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ê estiver implementando uma interface de linha de comando para algo. Agora você pode fazer o contrato que retorna null se não houver ação apropriada. Isso leva a verificação nula de que você está falando.

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

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

Comparar:

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

que é um design muito melhor porque leva a um código mais conciso.

Dito isso, talvez seja inteiramente apropriado que o método findAction () lance uma exceção com uma mensagem de erro significativa - especialmente neste caso em que você está confiando na entrada do usuário. Seria muito melhor para o método findAction lançar uma Exception do que para o método de chamada explodir com um 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, em vez de Do Nothing, sua ação padrão deve fornecer feedback ao usuário.

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

Uau, eu quase odeio adicionar outra resposta quando temos 57 maneiras diferentes de recomendar o NullObject pattern , mas acho que algumas pessoas interessadas nesta questão podem gostar de saber que há uma proposta na tabela para o Java 7 adicionar "null - manipulação segura " - uma sintaxe simplificada para a lógica if-not-equal-null.

O exemplo dado por Alex Miller é assim:

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

O ?. significa apenas desreferenciar o identificador esquerdo se ele não for nulo; caso contrário, avalie o restante da expressão como null . Algumas pessoas, como o membro do Java Posse, Dick Wall, e os eleitores da Devoxx realmente adoram essa proposta, mas também há oposição, sob a alegação de que ela realmente encorajaria mais o uso do null como um valor sentinela.

Atualização: Uma proposed para um operador seguro em nulo no Java 7 foi submetida sob o Project Coin. A sintaxe é um pouco diferente do exemplo acima, mas é a mesma noção.

Atualização: A proposta do operador sem nulo não entrou no Project Coin. Então, você não verá esta sintaxe no Java 7.


Comum "problema" em Java, de fato.

Primeiro, meus pensamentos sobre isso:

Eu considero que é ruim "comer" algo quando NULL foi passado, onde NULL não é um valor válido. Se você não está saindo do método com algum tipo de erro, significa que nada deu errado no seu método, o que não é verdade. Então você provavelmente retorna null neste caso, e no método de recebimento você novamente verifica null, e ele nunca termina, e você acaba com "if! = Null", etc.

Portanto, IMHO, null deve ser um erro crítico que impede a execução posterior (isto é, onde null não é um valor válido).

A maneira como eu resolvo este problema é esta:

Primeiro, sigo esta convenção:

  1. Todos os métodos públicos / API sempre verificam seus argumentos para null
  2. Todos os métodos privados não verificam null porque são métodos controlados (apenas deixe morrer com exceção nullpointer no caso de não ter sido tratado acima)
  3. Os únicos outros métodos que não verificam null são os métodos utilitários. Eles são públicos, mas se você os chamar por algum motivo, você sabe quais parâmetros você passa. Isto é como tentar ferver a água na chaleira sem fornecer água ...

E finalmente, no código, a primeira linha do método público é assim:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

Observe que addParam () retorna self, para que você possa adicionar mais parâmetros para verificar.

O método validate()será testado ValidationExceptionse algum dos parâmetros for nulo (marcado ou desmarcado é mais um problema de design / gosto, mas o meu ValidationExceptionestá marcado).

void validate() throws ValidationException;

A mensagem conterá o seguinte texto se, por exemplo, "planos" for nulo:

" Valor do argumento ilegal nulo é encontrado para o parâmetro [plans] "

Como você pode ver, o segundo valor no método addParam () (string) é necessário para a mensagem do usuário, porque você não pode facilmente detectar o nome da variável, mesmo com reflexão (não assunto desta postagem, de qualquer maneira ...).

E sim, sabemos que além dessa linha, não encontraremos mais um valor nulo, portanto, apenas invocaremos métodos com segurança nesses objetos.

Desta forma, o código é limpo, fácil de manter e legível.


Por fim, a única maneira de resolver completamente esse problema é usando uma linguagem de programação diferente:

  • Em Objective-C, você pode fazer o equivalente a invocar um método nile absolutamente nada acontecerá. Isso faz com que a maioria das verificações de nulo seja desnecessária, mas pode tornar os erros muito mais difíceis de diagnosticar.
  • Em Nice , uma linguagem derivada de Java, existem duas versões de todos os tipos: uma versão potencialmente nula e uma versão não nula. Você só pode invocar métodos em tipos não nulos. Tipos potencialmente nulos podem ser convertidos em tipos não nulos por meio da verificação explícita de nulo. Isso torna muito mais fácil saber onde as verificações nulas são necessárias e onde elas não estão.

Posso respondê-lo mais geralmente!

Nós geralmente enfrentam esse problema quando os métodos de obter os parâmetros na forma como não se espera (mau chamada de método é culpa do programador). Por exemplo: você espera obter um objeto, em vez disso, obtém um nulo. Você espera obter uma String com pelo menos um caractere, em vez disso, você recebe uma String vazia ...

Então não há diferença entre:

if(object == null){
   //you called my method badly!

}

ou

if(str.length() == 0){
   //you called my method badly again!
}

Ambos querem ter certeza de que recebemos parâmetros válidos antes de realizarmos outras funções.

Como mencionado em algumas outras respostas, para evitar problemas acima, você pode seguir o padrão Design por contrato . Por favor, veja http://en.wikipedia.org/wiki/Design_by_contract .

Para implementar este padrão em java, você pode usar as principais anotações do java como javax.annotation.NotNull ou usar bibliotecas mais sofisticadas como o Hibernate Validator .

Apenas uma amostra:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

Agora você pode desenvolver com segurança a função central de seu método sem precisar verificar os parâmetros de entrada, eles protegem seus métodos contra parâmetros inesperados.

Você pode ir além e certificar-se de que apenas pojos válidos possam ser criados em seu aplicativo. (amostra do site do validador de hibernação)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

Apenas não use nada nulo. Não permita isso.

Nas minhas classes, a maioria dos campos e variáveis ​​locais têm valores padrão não nulos, e eu adiciono declarações de contrato (always-on asserts) em todo o código para garantir que isso esteja sendo aplicado (já que é mais sucinto e mais expressivo do que permitir surgir como um NPE e depois ter que resolver o número da linha, etc.).

Depois de adotar essa prática, percebi que os problemas pareciam se consertar. Você pegaria coisas muito antes no processo de desenvolvimento apenas por acidente e perceberia que você tinha um ponto fraco ... e mais importante ... isso ajuda a encapsular diferentes preocupações dos módulos, diferentes módulos podem 'confiar' uns nos outros, e não mais sujar o código com if = null elseconstruções!

Esta é uma programação defensiva e resulta em código muito mais limpo a longo prazo. Sempre higienize os dados, por exemplo, aplicando padrões rígidos e os problemas desaparecem.

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

Os contratos são como testes de mini-unidade que estão sempre em execução, mesmo em produção, e quando as coisas falham, você sabe por que, ao invés de um NPE aleatório, você tem que descobrir de alguma forma.


Este é um problema muito comum para todos os desenvolvedores de Java. Portanto, há suporte oficial no Java 8 para resolver esses problemas sem código desordenado.

O Java 8 foi introduzido java.util.Optional<T>. É um contêiner que pode ou não ter um valor não nulo. O Java 8 forneceu uma maneira mais segura de manipular um objeto cujo valor pode ser nulo em alguns dos casos. É inspirado nas idéias de Haskell e Scala .

Em suma, a classe Optional inclui métodos para lidar explicitamente com os casos em que um valor está presente ou ausente. No entanto, a vantagem em relação às referências nulas é que a classe Optional <T> força você a pensar sobre o caso quando o valor não está presente. Como conseqüência, você pode evitar exceções de ponteiro nulo não intencionais.

No exemplo acima, temos uma fábrica de serviços domésticos que retorna um identificador para vários dispositivos disponíveis em casa. Mas esses serviços podem ou não estar disponíveis / funcionais; isso significa que pode resultar em um NullPointerException. Em vez de adicionar uma ifcondição nula antes de usar qualquer serviço, vamos incluí-lo em Opcional <Service>.

ENVOLVIMENTO À OPÇÃO <T>

Vamos considerar um método para obter uma referência de um serviço de uma fábrica. Em vez de retornar a referência de serviço, envolva-a com Opcional. Ele permite que o usuário da API saiba que o serviço retornado pode ou não estar disponível / funcional, usar defensivamente

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

Como você vê, Optional.ofNullable()é uma maneira fácil de obter a referência envolvida. Há outras maneiras de obter a referência do Opcional, ou Optional.empty()& Optional.of(). Um para retornar um objeto vazio em vez de retornar null e o outro para envolver um objeto não anulável, respectivamente.

ASSIM COMO EXATAMENTE AJUDA A EVITAR UMA VERIFICAÇÃO NULA?

Depois de ter envolvido um objeto de referência, o Optional fornece muitos métodos úteis para invocar métodos em uma referência agrupada sem NPE.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent invoca o Consumidor especificado com uma referência se for um valor não nulo. Caso contrário, não faz nada.

@FunctionalInterface
public interface Consumer<T>

Representa uma operação que aceita um único argumento de entrada e não retorna nenhum resultado. Ao contrário da maioria das outras interfaces funcionais, espera-se que o Consumidor opere por meio de efeitos colaterais. É tão limpo e fácil de entender. No exemplo de código acima, HomeService.switchOn(Service)será chamado se a referência de retenção Opcional não for nula.

Usamos o operador ternário com muita frequência para verificar a condição nula e retornar um valor alternativo ou um valor padrão. Opcional fornece outra maneira de lidar com a mesma condição sem marcar nulo. Optional.orElse (defaultObj) retorna defaultObj se o Opcional tiver um valor nulo. Vamos usar isso em nosso código de exemplo:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

Agora HomeServices.get () faz a mesma coisa, mas de uma maneira melhor. Verifica se o serviço já está inicializado de não. Se for, retorne o mesmo ou crie um novo novo serviço. Opcional <T> .orElse (T) ajuda a retornar um valor padrão.

Finalmente, aqui está o nosso NPE, bem como o código nulo livre de verificação:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

O post completo é o NPE, assim como o código Null check-free… Realmente? .


Eu gosto de artigos de Nat Pryce. Aqui estão os links:

Nos artigos há também um link para um repositório Git para um Java Maybe Type que eu acho interessante, mas eu não acho que isso sozinho poderia diminuir o inchaço do código de verificação. Depois de fazer algumas pesquisas na Internet, eu acho ! = Código nulo bloat poderia ser diminuído principalmente por um design cuidadoso.


Eu tentei o NullObjectPatternmas para mim nem sempre é o melhor caminho a percorrer. Às vezes, quando uma "não ação" não é apropriada.

NullPointerExceptioné uma exceção de tempo de execução que significa que é culpa dos desenvolvedores e com experiência suficiente, informa exatamente onde está o erro.

Agora para a resposta:

Tente tornar todos os seus atributos e acessores o mais privado possível ou evite expô-los aos clientes. Você pode ter os valores de argumento no construtor, é claro, mas ao reduzir o escopo, você não deixa a classe do cliente passar um valor inválido. Se você precisar modificar os valores, sempre poderá criar um novo object. Você verifica os valores no construtor apenas uma vez e, no restante dos métodos, pode ter quase certeza de que os valores não são nulos.

Claro, a experiência é a melhor maneira de entender e aplicar essa sugestão.

Byte!


Nulo não é um "problema". É parte integrante de um conjunto complete ferramentas de modelagem. O software visa modelar a complexidade do mundo e nulo carrega seu fardo. Nulo indica 'Sem dados' ou 'Desconhecido' em Java e afins. Por isso, é apropriado usar valores nulos para esses fins. Eu não prefiro o padrão 'Objeto nulo'; Eu acho que surge o ' quem vai guardar o problema dos guardiões '.
Se você me perguntar qual é o nome da minha namorada, eu lhe direi que não tenho namorada. Na linguagem Java, retornarei null. Uma alternativa seria lançar uma exceção significativa para indicar algum problema que não pode ser (ou não)t quer ser) resolvido ali mesmo e delegar em algum lugar mais alto na pilha para tentar novamente ou reportar erro de acesso a dados para o usuário.

  1. Para uma 'questão desconhecida' dê 'resposta desconhecida'. (Seja nulo-seguro onde isto é correto do ponto de vista de negócio) Verificando argumentos para null uma vez dentro de um método antes de uso alivia vários chamadores de verificá-los antes de uma chamada.

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

    Anterior leva ao fluxo de lógica normal para obter nenhuma foto de uma namorada inexistente da minha biblioteca de fotos.

    getPhotoOfThePerson(me.getGirlfriend())
    

    E isso se encaixa com o novo Java API (olhando para frente)

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

    Embora seja mais do que "fluxo de negócios normal" não encontrar fotos armazenadas no banco de dados para alguma pessoa, eu costumava usar pares como abaixo para alguns outros casos

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

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

    /**
     * @return photo or null
     */
    

    ou

    /**
     * @return photo, never null
     */
    
  2. Este é um caso bastante teórico e na maioria dos casos você deve preferir java null safe API (no caso de ser lançado em mais 10 anos), mas NullPointerExceptioné uma subclasse de um Exception. Assim, é uma forma de Throwableindicar condições que um aplicativo razoável pode querer capturar ( javadoc )! Para usar a primeira maior vantagem de exceções e separar o código de tratamento de erros do código 'regular' (de acordo com os criadores do Java ), é apropriado, quanto a mim, capturar NullPointerException.

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

    Perguntas podem surgir:

    P. e se getPhotoDataSource()retorna nulo?
    A. Cabe à lógica de negócios. Se eu não conseguir encontrar um álbum de fotos, não mostrarei fotos. E se appContext não for inicializado? A lógica de negócios deste método se compara a isso. Se a mesma lógica deve ser mais estrita, então lançar uma exceção é parte da lógica de negócios e a verificação explícita para null deve ser usada (caso 3). A nova API Java Null-safe se encaixa melhor aqui para especificar seletivamente o que implica e o que não implica ser inicializado para ser fail-fast em caso de erros do programador.

    Q. Código redundante pode ser executado e recursos desnecessários podem ser capturados.
    R. Poderia ocorrer se getPhotoByName()tentasse abrir uma conexão com o banco de dados, criar PreparedStatemente usar o nome da pessoa como um parâmetro SQL, por fim. A abordagem para uma questão desconhecida dá uma resposta desconhecida (caso 1) funciona aqui. Antes de pegar recursos, o método deve verificar os parâmetros e retornar o resultado 'desconhecido', se necessário.

    Q. Esta abordagem tem uma penalidade de desempenho devido à abertura do fechamento try.
    R. O software deve ser fácil de entender e modificar primeiro. Só depois disso, pode-se pensar em desempenho e somente se necessário! e onde necessário! ( source ) e muitos outros).

    PS. Essa abordagem será tão razoável quanto o uso do código de tratamento de erros separado do princípio de código "regular" for razoável para uso em algum lugar. Considere o próximo exemplo:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    PPS. Para aqueles que rápido a downvote (e não tão rápido para ler a documentação), gostaria de dizer que eu nunca peguei uma exceção de ponteiro nulo (NPE) na minha vida. Mas essa possibilidade foi intencionalmente projetada pelos criadores de Java porque o NPE é uma subclasse de Exception. Temos um precedente na história Java quando ThreadDeathé um Errornão porque é realmente um erro de aplicação, mas apenas porque não tinha a intenção de ser pego! Quanto NPE se encaixa para ser um do Errorque ThreadDeath! Mas não é.

  3. Verifique 'Não há dados' somente se a lógica de negócios implicar isso.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    e

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    Se appContext ou dataSource não for inicializado, o tempo de execução não manipulado NullPointerException eliminará o thread atual e será processado por Thread.defaultUncaughtExceptionHandler (para você definir e usar seu registrador favorito ou outro Thread.defaultUncaughtExceptionHandler notificação). Se não estiver definido, ThreadGroup#uncaughtException exibirá o ThreadGroup#uncaughtException para system err. Deve-se monitorar o log de erros do aplicativo e abrir o problema do Jira para cada exceção não tratada que, na verdade, é um erro de aplicativo. O programador deve corrigir o erro em algum lugar no material de inicialização.


O Guava, uma biblioteca central muito útil do Google, tem uma API interessante e útil para evitar nulos. Eu acho que o Guava muito útil.

Como explicado no wiki:

Optional<T>é uma maneira de substituir uma referência T anulável por um valor não nulo. Um Opcional pode conter uma referência T não nula (caso em que dizemos que a referência é "presente"), ou pode não conter nada (nesse caso, dizemos que a referência é "ausente"). Nunca é dito que "contém nulo".

Uso:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Provavelmente, a melhor alternativa para o Java 8 ou mais recente é usar a Optionalclasse.

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

Isso é especialmente útil para cadeias longas de possíveis valores nulos. Exemplo:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

Exemplo sobre como lançar exceção em null:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

O Java 7 introduziu o Objects.requireNonNullmétodo que pode ser útil quando algo deve ser verificado para não-nulidade. Exemplo:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}




null