Pergunta

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

Note que a resposta aceite pode estar fora de data, consulte https://stackoverflow.com/a/2386013/12943 para uma abordagem mais recente.

Foi útil?

Solução

Isso para mim soa como um problema razoavelmente comum que júnior para desenvolvedores intermediários tendem a enfrentar em algum momento: ou eles não sabem ou não confiar os contratos que estão participando e defensivamente overcheck para valores nulos. Além disso, ao escrever o seu próprio código, eles tendem a confiar em retornar valores nulos para indicar algo exigindo, portanto, a chamada para verificar se há valores nulos.

Para colocar isso de outra forma, há dois casos em que a verificação nula trata-se:

  1. Onde nula é uma resposta válida nos termos do contrato; e

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

(2) é fácil. Tanto declarações uso assert (afirmações) ou permitir que falha (por exemplo, NullPointerException ). Afirmações são uma característica Java altamente subutilizado que foi adicionado no 1.4. A sintaxe é:

assert <condition>

ou

assert <condition> : <object>

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

Uma declaração assert lança uma Error (AssertionError) se a condição não é verdade. Por padrão, Java ignora afirmações. Você pode ativar as afirmações, passando o -ea opção para a JVM. Você pode ativar e desativar afirmações para classes individuais e pacotes. Isso significa que você pode validar o código com as afirmações durante o desenvolvimento e teste, e desativá-los em um ambiente de produção, embora o meu testes mostraram ao lado de nenhum impacto no desempenho de afirmações.

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

(1) é um pouco mais difícil. Se você não tem nenhum controle sobre o código que você está chamando, em seguida, você está preso. Se nulo é uma resposta válida, você tem que verificar para ele.

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

.

Com os não-coleções pode ser mais difícil. Considere isso como um exemplo: se você tem essas interfaces:

public interface Action {
  void doSomething();
}

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

onde Parser leva entrada do usuário cru e encontra algo para fazer, talvez, se você está implementando uma interface de linha de comando para alguma coisa. Agora você pode fazer o contrato que ele retorna nulo se não há nenhuma ação apropriada. Que leva o nulo verificação que você está falando.

Uma solução alternativa é a de nunca retornar nulo e em vez disso usar o Null objeto padrão :

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

Compare:

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 projeto muito melhor, pois leva a mais de código conciso.

Dito isto, talvez, é inteiramente apropriado para o método findAction () para lançar uma exceção com uma mensagem de erro significativa - especialmente neste caso em que você está contando com a entrada do usuário. Seria muito melhor para o método findAction para lançar uma exceção do que para o método de chamada para 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 de try / catch é muito feio, ao invés do que faz nada sua ação padrão deve fornecer feedback para o 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);
        }
    }
}

Outras dicas

Se você usa (ou pretende usar) um IDE Java como JetBrains IntelliJ IDEA , Eclipse ou Netbeans ou uma ferramenta como findbugs então você pode usar anotações para resolver este problema.

@Nullable Basicamente, você tem e @NotNull.

Você pode usar no método e parâmetros, como este:

@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 pedaço de código:

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

Agora, o compilador IDEA IntelliJ irá dizer-lhe que o cheque é inútil, já que a função helloWorld() não voltará null, nunca.

Usando o parâmetro

void someMethod(@NotNull someParameter) { }

Se você escrever algo como:

someMethod(null);

Isso não irá compilar.

Última exemplo usando @Nullable

@Nullable iWantToDestroyEverything() { return null; }

Fazendo isso

iWantToDestroyEverything().something();

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

É uma boa maneira de deixar a verificação do compilador algo mais do que normalmente faz e fazer valer os seus contratos a ser mais forte. Infelizmente, não é apoiada por todos os compiladores.

Em IntelliJ IDEA 10.5 e sobre, eles adicionaram suporte para quaisquer outras implementações @Nullable @NotNull.

Veja o blog pós Mais flexível e configurável @ Nullable / @ NotNull anotações .

Se nulos valores não são permitidos

Se o seu método é chamado externamente, começar com algo como isto:

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

Em seguida, no restante desse método, você saberá que object não é nulo.

Se é um método interno (não faz parte de uma API), basta documento 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 passa o valor, e o método seguinte passa-lo etc. poderia ficar problemático. Nesse caso, você pode querer verificar o argumento como acima.

Se nulo é permitido

Isso realmente depende. Se descobrir que eu muitas vezes fazer algo como isto:

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

Então eu ramo, e fazer 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, eu deveria trabalhar na entrada, ou devo calcular um bom valor padrão?


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

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

Uau, eu quase odeio para adicionar outra resposta quando temos 57 maneiras diferentes para recomendar a NullObject pattern, mas acho que algumas pessoas interessadas nesta questão pode gostar de saber que há uma proposta sobre a mesa para Java 7 para adicionar "manipulação nulo-safe" -a simplificada sintaxe lógica se-não-igual-nulo.

O exemplo dado por Alex Miller parece com isso:

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

Os meios ?. única de-referência para o identificador esquerda se não for nula, de outro modo avaliar o restante da expressão como null. Algumas pessoas, como membro do Java Posse Dick Wall e a eleitores em Devoxx realmente amo esta proposta, mas não há oposição também, com o fundamento de que ele vai realmente incentivar mais uso de null como um valor de sentinela.


Atualização: Um proposta oficial para um operador nulo-safe em Java 7 foi apresentado no âmbito Projeto Coin. a sintaxe é um pouco diferente do exemplo acima, mas é a mesma noção.


Atualização: A proposta do operador nulo-safe não fazê-lo em Projeto Coin. Assim, você não vai estar vendo esta sintaxe em Java 7.

Se valores indefinidos não são permitidos:

Você pode configurar o IDE para avisá-lo sobre o potencial dereferencing nulo. Por exemplo. em Eclipse, consulte Preferências> Java> Compiler> Erros / Avisos / análise Null .

Se são permitidos valores indefinidos:

Se você quiser definir uma nova API, onde valores indefinidos faz sentido , use o Opção Padrão (pode ser familiar a partir de linguagens funcionais). Tem as seguintes vantagens:

  • É declarado explicitamente na API se uma entrada ou saída existe ou não.
  • Os compilador força você a lidar com o caso "indefinido".
  • Option é uma mônada , por isso não há necessidade de detalhado verificação nulo, mapa apenas use / foreach / getOrElse ou um combinator semelhante a usar com segurança o valor (exemplo) .

Java 8 tem um built-in Optional classe (recomendado); para versões anteriores, existem alternativas de biblioteca, por exemplo Goiaba 's < a href = "https://google.github.io/guava/releases/19.0/api/docs/com/google/common/base/Optional.html" rel = "noreferrer"> Optional ou FunctionalJava 's Option . Mas, como muitos padrões de estilo funcional, usando Option em Java (até 8) resulta em algum clichê, que você pode reduzir usando uma linguagem menos detalhada JVM, por exemplo, Scala ou Xtend.

Se você tem que lidar com uma API que pode retornar valores nulos , você não pode fazer muito em Java. Xtend e Groovy têm a Elvis ?: operador e operador dereference nulo-safe ?., mas note que este retorna nulo em caso de uma referência nula, por isso apenas" adia" o manuseio adequado de null.

Apenas para esta situação -

Não verificar se uma variável é nulo antes de chamar um método (uma string exemplo comparar abaixo) é igual a:

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

irá resultar em uma NullPointerException se foo não existe.

Você pode evitar que se você comparar suas Strings assim:

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

Com Java 8 vem a nova classe java.util.Optional que, sem dúvida, resolve alguns dos problemas. Uma lata pelo menos dizer que ele melhora a legibilidade do código, e no caso de APIs públicas fazem o contrato da API mais clara para o desenvolvedor de cliente.

Eles funcionam assim:

Um objeto opcional para um determinado tipo (Fruit) é criado como o tipo de retorno de um método. Ele 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 se busca uma lista de Fruit (fruits) de uma determinada ocorrê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 uma computação on - ou extrair um valor de - um objeto opcional. orElse() permite fornecer um retorno para valores em falta.

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

É claro que o cheque de valor nulo / vazio é ainda necessário, mas pelo menos o desenvolvedor está consciente de que o valor pode ser vazio e o risco de esquecer de verificação é limitado.

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

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

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

Eu os convido a ler este artigo (a minha principal fonte para escrever esta resposta) em que o NullPointerException (e no ponteiro geral null) problemática, bem como a solução (parcial) trazida por Optional estão bem explicadas: < a href = "http://java.dzone.com/articles/java-optional-objects" rel = "noreferrer"> Java opcional objetos .

Dependendo do tipo de objetos que está a verificar você pode ser capaz de usar algumas das classes nas apache commons, tais como: apache commons lang e Apache Commons coleções

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 um dos muitos; existem algumas boas aulas de bens comuns que fazem a manipulação segura nulo.

Aqui segue um exemplo de como você pode usar vallidation nula em JAVA quando você incluir apache biblioteca (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 Spring, Spring, também tem a mesma funcionalidade em seu pacote, consulte biblioteca (primavera-2.4.6.jar)

Exemplo de como usar este classf estática de mola (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • Se você considerar um objeto não deve ser nulo (ou é um bug) usar uma declaração.
  • Se o método não aceita parâmetros nulos dizê-lo no javadoc e usar uma declaração.

Você tem que verificar se há objeto! = Null somente se você deseja lidar com o caso em que o objeto pode ser nulo ...

Há uma proposta de acrescentar novas anotações em Java7 para ajudar com nulo / notnull params: http://tech.puredanger.com/java7/#jsr308

Eu sou um fã de código "falhar rapidamente". 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 ele nunca deve ser nulo, em primeiro lugar, em seguida, ignorá-lo e permitir que um NullPointerException para ser jogado. O código de chamada fará tanto sentido de uma NPE como seria uma IllegalArgumentException, mas vai ser mais fácil para o desenvolvedor para depurar e entender o que deu errado se uma NPE é jogado em vez de seu código tentar executar alguma outra contingência inesperada lógica - que em última análise resulta na aplicação não de qualquer maneira.

Os Google oferece-quadro coleções uma boa e maneira elegante de alcançar o cheque nulo.

Há um método em uma classe biblioteca como esta:

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

E o uso é (com import static):

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

Ou no seu exemplo:

checkNotNull(someobject).doCalc();

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

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

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

Ao invés de Null Padrão Object - que tem seus usos -. Você pode considerar situações em que o objeto nulo é um bug

Quando a exceção é lançada, examine o rastreamento de pilha e de trabalho através do bug.

Java 7 tem uma nova classe de utilitário java.util.Objects em que existe um método requireNonNull(). Tudo isso faz é jogar uma NullPointerException se seu argumento é nulo, mas ele limpa o código um pouco. Exemplo:

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

O método é mais útil para verificando pouco antes de uma atribuição em um construtor, onde cada uso dele pode salvar três linhas de código:

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

se torna

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

Null não é um 'problema'. É uma parte integrante de um completa conjunto de ferramentas de modelagem. objetivos software para modelar a complexidade do mundo e nulos leva o seu fardo. Null indica 'Não há dados' ou 'Desconhecido' em Java e afins. Por isso, é apropriado usar nulos para esses fins. Eu não prefiro o padrão 'Null objeto'; Eu acho que subir o ' que guardará os guardiões ' problema.
Se você me perguntar qual é o nome da minha namorada eu vou te dizer que eu não tenho namorada. Na linguagem Java eu ??vou retornar nulo. Uma alternativa seria a de lançar exceção significativa para indicar algum problema que não pode ser (ou não querem ser) resolvido ali mesmo e delegá-la em algum lugar mais elevado na pilha para repetir ou relatório de erro de acesso de dados para o usuário.

  1. Para uma 'questão desconhecida' dar 'resposta desconhecida'. (ser nulo-safe, onde isso é correto do ponto de vista empresarial) Verificação argumentos para nula, uma vez dentro de um método antes do 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.
    }
    

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

    getPhotoOfThePerson(me.getGirlfriend())
    

    E ele se encaixa com nova vinda API Java (ansioso)

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

    Embora seja bastante 'fluxo de negócios normal' não encontrar foto armazenada na base de dados por 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 para não detesta digitar <alt> + <shift> + <j> (gerar javadoc em Eclipse) e escrever três palavras adicionais para você API pública. Este será mais do que suficiente para todos, mas aqueles que não ler a documentação.

    /**
     * @return photo or null
     */
    

    ou

    /**
     * @return photo, never null
     */
    
  2. Esta é caso bastante teórica e na maioria dos casos você deve preferir java API segura nulo (no caso, será lançado em mais 10 anos), mas NullPointerException é subclasse de um Exception. assim, é uma forma de Throwable que indica condições que uma aplicação razoável pode querer catch ( javadoc )! Para usar o primeiro mais vantagem de exceções e separar o código a partir do código 'regular' (de tratamento de erros acordo com criadores de Java ) é apropriado, quanto a mim, para pegar NullPointerException.

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

    As perguntas podem surgir:

    Q. E se getPhotoDataSource() retorna nulo?
    A. Cabe a lógica de negócios. Se eu não encontrar um álbum de foto que eu vou lhe mostrar não há fotos. E se appContext não é inicializado? lógica de negócios deste método coloca-se com isso. Se a mesma lógica deve ser mais rigoroso, em seguida, lançar uma exceção é parte da lógica de negócios e verificação explícita para nula deve ser usada (caso 3). Os novas Java fits API Null-seguras melhor aqui para especificar seletivamente o que implica eo que não implica ser inicializado para ser fail-fast em caso de erros programador.

    Q. código redundante pudessem ser executadas e recursos desnecessários poderiam ser agarrado.
    A. Ele poderia ter lugar se getPhotoByName() iria tentar abrir uma conexão de banco de dados, criar PreparedStatement e usar o nome da pessoa como um parâmetro SQL no último. A abordagem para uma questão desconhecida dá uma resposta desconhecida (caso 1) trabalha aqui. Antes recursos agarrando o método deve verificar parâmetros e retorno resultado 'desconhecido', se necessário.

    Q. Esta abordagem tem uma penalidade de desempenho devido à abertura fechamento tentativa.
    A. Software deve ser fácil de entender e modificar em primeiro lugar. Somente após isso, pode-sepensar sobre o desempenho, e somente se necessário! e onde for necessário! ( fonte ), e muitos outros).

    PS. Esta abordagem será tão razoável para usar como o código de tratamento de erros separado do código "regular" princípio é razoável usar em algum lugar. Considere o seguinte 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 rápido para downvote (e não tão rápido para ler a documentação) Eu gostaria de dizer que eu nunca tinha pego uma exceção nula-ponteiro (NPE) em minha vida. Mas esta possibilidade foi projetado intencionalmente pelos criadores de Java porque NPE é uma subclasse de Exception. Temos um precedente na história Java quando ThreadDeath é um Error nã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 Error que ThreadDeath! Mas não é.

  3. Verificar 'Não há dados' somente se a lógica de negócio implica-lo.

    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 é inicializado NullPointerException runtime não tratada vai matar thread atual e será processado por Thread.defaultUncaughtExceptionHandler (para você definir e usar o seu logger favorito ou outro mechanizm notificação). Se não estiver definido, ThreadGroup # uncaughtException imprimirá stacktrace para err sistema. Deve-se monitorar o log de erro aplicativo e abra questão Jira para cada exceção não tratada que na verdade é erro de aplicação. Programador deve corrigir bug em algum lugar coisas inicialização.

Em última análise, a única maneira de resolver completamente este problema é usando uma linguagem de programação diferente:

  • Em Objective-C, você pode fazer o equivalente a chamar um método em nil, e absolutamente nada acontecerá. Isso faz com que a maioria das verificações nulos desnecessário, mas pode cometer erros muito mais difícil de diagnosticar.
  • Na agradável , uma linguagem Java derivadas, existem duas versões de todos os tipos : uma versão potencialmente nulo e uma versão não-nulo. Você só pode chamar métodos em tipos não-nulos. Potencialmente nulos tipos podem ser convertidos em tipos não-nulos através de verificação explícita para null. Isso torna muito mais fácil saber onde verificações nulos são necessárias e onde elas não são.

Common "problema" em Java, de fato.

Em primeiro lugar, os meus pensamentos sobre isso:

Eu considero que é ruim "comer" alguma coisa 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, em seguida, isso não significa nada deu errado em seu método que não é verdade. Então você provavelmente retornar nulo neste caso, e no método de recepção de novo buscar por nulo, e isso nunca acaba, e você acaba com "if! = Null", etc ..

Assim, IMHO, null deve ser um erro crítico que impede ainda mais a execução (ou seja, onde nulo não é um valor válido).

A forma como eu resolver este problema é o seguinte:

Primeiro, eu seguir esta convenção:

  1. todos os métodos públicos / API sempre verificar seus argumentos para nula
  2. Todos métodos privados não verificar se há nula, uma vez que são controlados métodos (apenas deixar morrer com exceção nullpointer caso não foi tratado acima)
  3. Os únicos outros métodos que não verificar NULL são métodos utilitários. Eles são públicos, mas se você chamá-los por algum motivo, você sabe quais parâmetros passar. Isto é como tentar ferver a água na chaleira sem fornecimento de água ...

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

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

Note que AddParam () retorna auto, para que você possa adicionar mais parâmetros para verificar.

Método validate() vai jogar ValidationException verificado se qualquer um dos parâmetros é nulo (marcada ou desmarcada é mais uma questão de design / gosto, mas meu ValidationException está marcada).

void validate() throws ValidationException;

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

" nulo valor do argumento ilegal é encontrado para o parâmetro [planos] "

Como você pode ver, o segundo valor na AddParam () método (string) é necessário para a mensagem do usuário, porque você não pode facilmente detectar passou-in nome da variável, mesmo com reflexão (não sujeitos deste post de qualquer maneira .. .).

E sim, nós sabemos que para além desta linha já não vai encontrar um valor nulo por isso, só com segurança invocar métodos nesses objetos.

Desta forma, o código é limpo, fácil manutenção e legível.

solicitando que pontos de interrogação que você pode estar interessado em estratégias de tratamento de erros. arquiteto da sua equipe deve decidir como trabalhar erros. Existem várias maneiras de fazer isso:

  1. permitir que as exceções a ondular através -. Captura-los no 'loop principal' ou em alguma outra rotina de gestão

    • Verificar as condições de erro e tratá-los adequadamente

Claro que sim ter um olhar para Aspect Oriented Programming, também - eles têm formas puras para inserir if( o == null ) handleNull() em seu bytecode

.

Além de usar assert você pode usar o seguinte:

if (someobject == null) {
    // Handle null here then move on.
}

Este é ligeiramente melhor do que:

if (someobject != null) {
    .....
    .....



    .....
}

Há pouco já não usar nulo. Não permita que isso.

Em minhas aulas, a maioria dos campos e variáveis ??locais têm valores padrão não nulos, e eu adicionar instruções de contrato (always-on afirma) em todo o código para garantir que este está sendo executada (já que é mais sucinto e mais expressiva de deixá-lo vir para cima como um NPE e depois ter que resolver o número da linha, etc.).

Uma vez eu adotei essa prática, notei que os problemas parecia fixar-se. Você pegaria as coisas muito mais cedo no processo de desenvolvimento apenas por acidente e perceber que você tinha um ponto fraco .. e mais importante .. ajuda de diferentes preocupações, diferentes módulos podem 'Encapsular módulos confiança' entre si, e não mais que desarrumam o código com construções if = null else!

Esta é a programação defensiva e resulta em um código mais limpo muito no longo prazo. Sempre higienizar os dados, por exemplo aqui através da aplicação de normas rígidas, e os problemas vão embora.

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-unitários que estão sempre correndo, mesmo em produção, e quando as coisas falham, você sabe por que, em vez de uma NPE aleatória você tem que descobrir alguma forma para fora.

Goiaba, uma biblioteca central muito útil pelo Google, tem um agradável e API útil nulos Evitar. Acho UsingAndAvoidingNullExplained muito útil.

Como explicado na wiki:

Optional<T> é uma maneira de substituir uma referência T anulável com um valor não nulo. Um opcional pode conter qualquer um de referência T não nulo (Caso em que dizemos a referência é "presente"), ou pode conter nada (caso em que dizemos a referência é "ausente"). Nunca é disse a "conter nulo."

Uso:

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

Este é um problema muito comum para todos os desenvolvedores Java. Portanto, não há apoio oficial em Java 8 para abordar estas questões, sem código desordenado.

Java 8 introduziu java.util.Optional<T>. É um recipiente que pode ou não pode conter um valor não nulo. Java 8 deu uma maneira mais segura de lidar com um objeto cujo valor pode ser nulo em alguns dos casos. É inspirado a partir das idéias de Haskell e Scala .

Em poucas palavras, a classe opcional inclui métodos para lidar explicitamente com os casos em que um valor está presente ou ausente. No entanto, a vantagem em relação à referência nula é que os Opcional classe 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ço de casa que retorna um identificador para vários aparelhos disponíveis na casa. Mas estes serviços podem ou não estar disponível / funcional; isso significa que pode resultar em um NullPointerException. Em vez de adicionar uma condição nula if antes de usar qualquer serviço, vamos envolvê-la em até Opcional .

ENVOLVIMENTO DE OPÇÃO

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, envolvê-lo com opcional. Ele permite que o know utilizador API que o serviço retornou pode ou não disponível / funcional, uso defensivamente

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

Como você vê Optional.ofNullable() fornece uma maneira fácil de obter a referência embrulhado. Há outras maneiras de obter a referência do Opcional, seja Optional.empty() & Optional.of(). Um para retornar um objeto vazio em vez de retuning nula e outro para embrulhar um objeto não nulo, respectivamente.

Então, como exatamente ele ajuda a evitar A NULL cheque?

Depois de ter embrulhado um objeto de referência, opcional fornece muitos métodos úteis para invocar métodos em uma referência envolto sem NPE.

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

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

@FunctionalInterface
public interface Consumer<T>

Representa uma operação que aceita um único argumento de entrada e retorna qualquer resultado. Ao contrário da maioria de outras interfaces funcionais, consumidor espera-se que operam através de efeitos colaterais. É tão limpo e fácil de entender. No exemplo de código acima, HomeService.switchOn(Service) é invocado se a referência realização opcional não é nulo.

Nós usamos o operador ternário muito frequentemente para verificar a condição nula e retornar um valor alternativo ou valor padrão. Opcional fornece uma outra maneira de lidar com a mesma condição sem verificar nulo. Optional.orElse (defaultObj) retorna defaultObj se o opcional tem 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 mesma coisa, mas de uma maneira melhor. Ele verifica se o serviço já foi inicializado de não. Se for, em seguida, retornar o mesmo ou criar um novo New serviço. Opcional .orElse (T) ajuda a devolver um valor padrão.

Finalmente, aqui é a nossa NPE, bem como código livre de verificação nulo:

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 é NPE, bem como código livre de verificação nulo ... Realmente? .

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

Nos artigos também há um link para um repositório Git para um Java Talvez Digite o que eu acho interessante, mas eu não acho que isso só poderia diminuir o verificando bloat código. Depois de fazer algumas pesquisas na internet, eu acho que ! = Null bloat código poderia ser diminuída principalmente pelo design cuidado.

Eu tentei o NullObjectPattern mas para mim não é sempre o melhor caminho a percorrer. Há, por vezes, quando um "nenhuma ação" não é apropriada.

NullPointerException é uma Runtime exceção isso significa que é desenvolvedores de falha e com experiência suficiente que lhe diz exatamente onde está o erro.

Agora, para a resposta:

Tente fazer todos os seus atributos e seus assessores mais privado possível ou evite expô-los aos clientes em todos os. Você pode ter os valores de argumento no construtor é claro, mas através da redução do escopo que você não deixe a classe do cliente passar um valor inválido. Se você precisar modificar os valores, você sempre pode criar uma nova object. Você verificar os valores no construtor única uma vez e no resto dos métodos que você pode ter quase a certeza de que os valores não são nulos.

É claro que a experiência é a melhor maneira de compreender e aplicar esta sugestão.

Byte!

Provavelmente a melhor alternativa para Java 8 ou mais recente é usar o classe Optional .

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

Isto é especialmente útil para longas cadeias 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 de como jogar exceção no nulo:

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

Java 7 introduziu o Objects.requireNonNull método que pode ser útil quando algo deve ser verificado para não-nullness. Exemplo:

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

Maio I respondê-la de forma mais geral!

normalmente rosto esta questão 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 você obter um nulo. Você espera para obter uma string com pelo menos um caractere, em vez você recebe uma String vazia ...

Portanto, 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 fazer quaisquer outras funções.

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

Para implementar esse padrão em java, você pode usar anotações Java essenciais como javax.annotation.NotNull ou usar bibliotecas mais sofisticados como Hibernate Validator .

Apenas um exemplo:

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

Agora você pode desenvolver com segurança a função de núcleo de seu método sem a necessidade de verificar os parâmetros de entrada, eles guardam os seus métodos de parâmetros inesperados.

Você pode ir um passo adiante e se certificar de que apenas pojos válidos poderiam ser criados na sua aplicação. (Amostra a partir do site 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;

   // ...
}

Eu altamente ignorar respostas que sugiro usar os objetos nulos em cada situação. Este padrão pode quebrar o contrato e enterrar os problemas cada vez mais fundo em vez de resolvê-los, não mencionar que usado de forma inadequada criará outra pilha de código clichê que vai exigir manutenção futura.

Na realidade, se algo retornado de um método pode ser nulo e o código de chamada tem que tomar uma decisão sobre isso, não deve uma chamada anterior que garante o estado.

Também tenha em mente, que o padrão nulo objeto será memória fome se usado sem cuidado. Por isso -. A instância de um NullObject deve ser compartilhada entre os proprietários, e não ser uma instância unigue para cada um deles

Também eu não recomendo usar este padrão onde o tipo é destinado a ser uma representação tipo primitivo - como entidades matemáticas, que não são escalares: vetores, matrizes, números complexos e POD (Plain Old Dados) objetos, que se destinam para manter estado na forma de Java built-in tipos. Neste último caso, você iria acabar chamando métodos getter com resultados arbitrários. Por exemplo, o que deve um NullPerson.getName () método de retorno?

Vale a pena considerar tais casos, a fim de evitar resultados absurdos.

  1. variáveis ??Nunca inicializar a null.
  2. Se (1) não é possível, inicialize todas as coleções e matrizes para esvaziar coleções / matrizes.

Fazer isso em seu próprio código e você pode evitar! = Verificações nulos.

Na maioria das vezes verificações nulos parecem loops de guarda sobre coleções ou arrays, então apenas Inicializar-los vazio, você não vai precisar de qualquer verificação de nulos.

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

Há uma pequena sobrecarga nisso, mas vale a pena para um código mais limpo e menos NullPointerExceptions.

Este é o erro ocorreu mais comum para a maioria dos desenvolvedores.

Temos várias maneiras de lidar com isso.

Abordagem 1:

org.apache.commons.lang.Validate //using apache framework

NOTNULL (object Object, String message)

Abordagem 2:

if(someObject!=null){ // simply checking against null
}

Abordagem 3:

@isNull @Nullable  // using annotation based validation

Abordagem 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top