O que é uma NullPointerException e como corrigi-la?


210

O que são exceções de ponteiro nulo ( java.lang.NullPointerException) e o que as causa?

Quais métodos / ferramentas podem ser usados ​​para determinar a causa e impedir que a exceção faça com que o programa seja encerrado prematuramente?

Respostas:


3764

Quando você declara uma variável de referência (ou seja, um objeto), está realmente criando um ponteiro para um objeto. Considere o seguinte código em que você declara uma variável do tipo primitivo int:

int x;
x = 10;

Neste exemplo, a variável xé an inte Java a inicializará 0para você. Quando você atribui o valor de 10na segunda linha, seu valor de 10é gravado no local de memória referido por x.

Mas, quando você tenta declarar um tipo de referência , algo diferente acontece. Pegue o seguinte código:

Integer num;
num = new Integer(10);

A primeira linha declara uma variável chamada num, mas ainda não contém um valor primitivo. Em vez disso, ele contém um ponteiro (porque o tipo é o tipo de Integerreferência). Como você ainda não disse o que apontar, o Java define como null, o que significa " Não estou apontando para nada ".

Na segunda linha, a newpalavra-chave é usada para instanciar (ou criar) um objeto do tipo Integere a variável ponteiro numé atribuída a esse Integerobjeto.

Isso NullPointerExceptionocorre quando você declara uma variável, mas não cria um objeto e atribui à variável antes de tentar usar o conteúdo da variável (chamada de desreferenciação ). Então você está apontando para algo que realmente não existe.

A desreferenciação geralmente ocorre quando se usa .para acessar um método ou campo, ou se usa [para indexar uma matriz.

Se você tentar remover a referência numantes de criar o objeto, receberá um NullPointerException. Nos casos mais triviais, o compilador detectará o problema e informará " num may not have been initialized," mas às vezes você pode escrever um código que não cria diretamente o objeto.

Por exemplo, você pode ter um método da seguinte maneira:

public void doSomething(SomeObject obj) {
   //do something to obj
}

Nesse caso, você não está criando o objeto obj, mas assumindo que ele foi criado antes da doSomething()chamada do método. Observe que é possível chamar o método assim:

doSomething(null);

Nesse caso, objé null. Se o método se destina a fazer algo com o objeto passado, é apropriado lançar o arquivo NullPointerExceptionporque é um erro do programador e o programador precisará dessas informações para fins de depuração. Inclua o nome da variável de objeto na mensagem de exceção, como

Objects.requireNonNull(a, "a");

Como alternativa, pode haver casos em que o objetivo do método não é operar apenas no objeto passado e, portanto, um parâmetro nulo pode ser aceitável. Nesse caso, você precisaria verificar um parâmetro nulo e se comportar de maneira diferente. Você também deve explicar isso na documentação. Por exemplo, doSomething()poderia ser escrito como:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       //do something
    } else {
       //do something else
    }
}

Por fim, como identificar a exceção e a causa usando o rastreamento de pilha

Quais métodos / ferramentas podem ser usados ​​para determinar a causa e impedir que a exceção faça com que o programa seja encerrado prematuramente?

O sonar com findbugs pode detectar o NPE. O sonar pode capturar exceções de ponteiro nulo causadas pela JVM Dynamically


558
"A melhor maneira de evitar esse tipo de exceção é sempre procurar nulo quando você não criou o objeto." Se o chamador passa nulo, mas nulo não é um argumento válido para o método, é correto lançar a exceção de volta no chamador, porque é culpa do chamador. Ignorar silenciosamente as entradas inválidas e não fazer nada no método é um conselho extremamente ruim, pois oculta o problema.
Boann

104
Eu acrescentaria uma observação sobre este post, explicando que mesmo atribuições a primitivas podem causar NPEs ao usar a caixa automática: int a=bpode lançar um NPE se b for an Integer. Há casos em que isso é confuso para depuração.
Simon Fischer

58
É possível NPE captura lançada por um webapp do navegador de internet como ele irá mostrar na fonte de exibição de página do navegador de internet ..?
Sid

76
Sim, verifique se o objeto é igual a nulo antes de chamar um método ou tentar acessar uma variável que possa ter. Algumas vezes, a estruturação do seu código pode ajudar a evitar a exceção de ponteiro nulo. por exemplo, ao verificar uma string de entrada com uma string constante, você deve começar com a string constante como aqui: if ("SomeString" .equals (inputString)) {} // mesmo se inputString for nulo, nenhuma exceção será lançada. Portanto, existem várias coisas que você pode fazer para tentar estar seguro.
Rose

78
Uma maneira adicional de evitar NullPointerExceptionproblemas em seu código é usar @Nullablee @NotNullanotações. A resposta a seguir tem mais informações sobre isso. Embora essa resposta seja específica sobre o IntelliJ IDE, ela também é aplicável a outras ferramentas, como é o aparato dos comentários. (BTW eu não estou autorizado a editar esta resposta diretamente, talvez o autor pode adicioná-lo?)
Arjan Mels

879

NullPointerExceptions são exceções que ocorrem quando você tenta usar uma referência que aponta para nenhum local na memória (nulo) como se estivesse fazendo referência a um objeto. Chamar um método em uma referência nula ou tentar acessar um campo de uma referência nula acionará a NullPointerException. Essas são as mais comuns, mas outras maneiras estão listadas na NullPointerExceptionpágina javadoc.

Provavelmente, o código de exemplo mais rápido que eu poderia criar para ilustrar um NullPointerExceptionseria:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

Na primeira linha dentro main, estou explicitamente definindo a Objectreferência objigual a null. Isso significa que eu tenho uma referência, mas não está apontando para nenhum objeto. Depois disso, tento tratar a referência como se ela apontasse para um objeto chamando um método nele. Isso resulta em um NullPointerExceptionporque não há código a ser executado no local que a referência está apontando.

(Isso é um detalhe técnico, mas acho que vale a pena mencionar: uma referência que aponta para nulo não é a mesma que um ponteiro C que aponta para um local de memória inválido. Um ponteiro nulo literalmente não está apontando para nenhum lugar , que é sutilmente diferente de apontando para um local que é inválido.)


49
Entendi tudo o que você escreveu lá, mas apenas porque estou codificando há um tempo e sei o que é um 'ponteiro' e uma 'referência' (e o que é nulo, nesse caso). Quando tento me aprofundar em explicações como essa, meus alunos olham para mim com um ar de desespero, porque não há antecedentes suficientes.
mmr

33
@ mmr: Obrigado pelo feedback, você faz uma observação válida. É difícil na internet julgar realmente onde alguém está e em que nível é seguro começar uma explicação. Vou tentar revisar isso novamente.
Bill o Lagarto

22
Uma maneira mais comum de obter uma NullPointerException na prática seria esquecer de inicializar explicitamente uma variável de membro para algo diferente de nullantes de usá-la, assim . Com variáveis ​​locais, o compilador capturaria esse erro, mas neste caso não. Talvez isso faça uma adição útil à sua resposta?
Ilmari Karonen

6
@EJP Acho que seus pontos são válidos, por isso atualizei a resposta para ficar mais clara e evitar dizer 'pontos nulos' onde isso aconteceu.
21416 Steve Powell

5
@StevePowell Indiquei há muito tempo que não queria que minha resposta mudasse. Por favor, respeite a intenção do autor original.
Bill o Lagarto

696

O que é uma NullPointerException?

Um bom lugar para começar é o JavaDocs . Eles têm isso coberto:

Lançado quando um aplicativo tenta usar null em um caso em que um objeto é necessário. Esses incluem:

  • Chamando o método de instância de um objeto nulo.
  • Acessando ou modificando o campo de um objeto nulo.
  • Tomando o comprimento de null como se fosse uma matriz.
  • Acessando ou modificando os slots nulos como se fosse uma matriz.
  • Lançar nulo como se fosse um valor Throwable.

Os aplicativos devem lançar instâncias dessa classe para indicar outros usos ilegais do objeto nulo.

Também é o caso que, se você tentar usar uma referência nula synchronized, isso também lançará essa exceção, de acordo com o JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Caso contrário, se o valor da Expressão for nulo, a NullPointerExceptionserá lançado.

Como faço para corrigir isso?

Então você tem um NullPointerException. Como você conserta isso? Vamos dar um exemplo simples que lança um NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Identifique os valores nulos

A primeira etapa é identificar exatamente quais valores estão causando a exceção . Para isso, precisamos fazer alguma depuração. É importante aprender a ler um rastreamento de pilha . Isso mostrará onde a exceção foi lançada:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Aqui, vemos que a exceção é lançada na linha 13 (no printStringmétodo). Observe a linha e verifique quais valores são nulos adicionando instruções de log ou usando um depurador . Descobrimos que sé nulo, e chamar o lengthmétodo nele lança a exceção. Podemos ver que o programa para de lançar a exceção quando s.length()é removido do método.

Rastreie de onde vêm esses valores

Em seguida, verifique de onde vem esse valor. Seguindo os chamadores do método, vemos que ele sé passado com printString(name)no print()método e this.nameé nulo.

Rastreie onde esses valores devem ser definidos

Onde está this.namedefinido? No setName(String)método Com um pouco mais de depuração, podemos ver que esse método não é chamado. Se o método foi chamado, verifique a ordem em que esses métodos são chamados e o método set não é chamado após o método de impressão.

Isso é suficiente para nos dar uma solução: adicione uma chamada printer.setName()antes de ligar printer.print().

Outras correções

A variável pode ter um valor padrão (e setNamepode impedir que seja definido como nulo):

private String name = "";

O método printou printStringpode procurar nulo , por exemplo:

printString((name == null) ? "" : name);

Ou você pode criar a classe para que name sempre tenha um valor não nulo :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

Veja também:

Ainda não consigo encontrar o problema

Se você tentou depurar o problema e ainda não tem uma solução, pode postar uma pergunta para obter mais ajuda, mas inclua o que tentou até agora. No mínimo, inclua o rastreamento de pilha na pergunta e marque os números de linha importantes no código. Além disso, tente simplificar o código primeiro (consulte SSCCE ).


44
+1 É bom ter um exemplo que inclua percorrer o rastreamento de pilha; é importante mostrar por que a leitura é importante para depurar o NPE. (e por isso que quase sempre procurar um stacktrace quando alguém postar uma pergunta sobre um erro)
Dennis Meng

16
Você mencionou a depuração ... Como isso funciona? Estou pesquisando o assunto há algum tempo, mas não consigo encontrar nada. Tenho certeza que um professor incrível como você pode me ensinar em um segundo! Muito obrigado! :-)
Ruchir Baronia

15
@RuchirBaronia Um depurador permite percorrer um programa linha por linha para ver quais métodos são chamados e como as variáveis ​​são alteradas. Os IDEs devem ter algumas ferramentas para fazer isso. Consulte vogella.com/tutorials/EclipseDebugging/article.html, por exemplo.
fgb

15
@RuchirBaronia Você define pontos de interrupção nos métodos em torno de qualquer NullPointerExceptions como visto no stacktrace e verifica os valores das variáveis ​​com relação ao que você espera que elas sejam. Se você souber que uma variável é nula quando não deveria ser, poderá definir pontos de interrupção em torno de qualquer código que altere o valor. Também existem pontos de interrupção condicionais que você pode usar, que informarão quando um valor for alterado.
fgb

6
Definir objetos String como uma string vazia como seu valor padrão é considerado uma prática ruim.
minúsculo

501

Pergunta: O que causa um NullPointerException(NPE)?

Como você deve saber, tipos Java são divididos em tipos primitivos ( boolean, int, etc.) e tipos de referência . Os tipos de referência em Java permitem que você use o valor especial, nullque é a maneira como Java diz "nenhum objeto".

A NullPointerExceptioné lançado em tempo de execução sempre que seu programa tenta usar a nullcomo se fosse uma referência real. Por exemplo, se você escrever isto:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

a instrução rotulada "AQUI" tentará executar o length()método em uma nullreferência, e isso lançará a NullPointerException.

Existem várias maneiras de usar um nullvalor que resultará em a NullPointerException. De fato, as únicas coisas que você pode fazer nullsem causar um NPE são:

  • atribua-o a uma variável de referência ou leia-o a partir de uma variável de referência,
  • atribua-o a um elemento da matriz ou leia-o a partir de um elemento da matriz (desde que a própria referência da matriz seja não nula!),
  • passe como parâmetro ou retorne como resultado ou
  • testá-lo usando as ==ou !=operadores, ou instanceof.

Pergunta: Como leio o NPE StackTrace?

Suponha que eu compile e execute o programa acima:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

Primeira observação: a compilação foi bem sucedida! O problema no programa não é um erro de compilação. É um erro de tempo de execução. (Alguns IDEs podem avisar que seu programa sempre gera uma exceção ... mas o javaccompilador padrão não.)

Segunda observação: quando executo o programa, ele produz duas linhas de "gobbledy-gook". ERRADO!! Isso não é bobagem. É um rastreamento de pilha ... e fornece informações vitais que o ajudarão a rastrear o erro no seu código, se você ler atentamente.

Então, vejamos o que diz:

Exception in thread "main" java.lang.NullPointerException

A primeira linha do rastreamento da pilha informa várias coisas:

  • Ele informa o nome do encadeamento Java no qual a exceção foi lançada. Para um programa simples com um thread (como este), ele será "main". Vamos continuar ...
  • Ele informa o nome completo da exceção que foi lançada; ie java.lang.NullPointerException.
  • Se a exceção tiver uma mensagem de erro associada, ela será exibida após o nome da exceção. NullPointerExceptioné incomum nesse sentido, porque raramente tem uma mensagem de erro.

A segunda linha é a mais importante no diagnóstico de um NPE.

at Test.main(Test.java:4)

Isso nos diz várias coisas:

  • "at Test.main" diz que estávamos no mainmétodo da Testclasse.
  • "Test.java:4" fornece o nome do arquivo de origem da classe E indica que a instrução em que isso ocorreu está na linha 4 do arquivo.

Se você contar as linhas no arquivo acima, a linha 4 é a que eu identifiquei com o comentário "AQUI".

Observe que em um exemplo mais complicado, haverá muitas linhas no rastreamento de pilha do NPE. Mas você pode ter certeza de que a segunda linha (a primeira linha "at") informará onde o NPE foi lançado 1 .

Em resumo, o rastreamento da pilha nos dirá inequivocamente qual declaração do programa lançou o NPE.

1 - Não é bem verdade. Existem coisas chamadas exceções aninhadas ...

Pergunta: Como rastrear a causa da exceção NPE no meu código?

Esta é a parte difícil. A resposta curta é aplicar inferência lógica às evidências fornecidas pelo rastreamento de pilha, o código-fonte e a documentação relevante da API.

Vamos ilustrar com o exemplo simples (acima) primeiro. Começamos olhando para a linha que o rastreamento de pilha nos disse é onde o NPE aconteceu:

int length = foo.length(); // HERE

Como isso pode gerar um NPE?

De fato, existe apenas uma maneira: isso só pode acontecer se footiver o valor null. Em seguida, tentamos executar o length()método nulle ... BANG!

Mas (eu ouvi você dizer) e se o NPE fosse lançado dentro da length()chamada de método?

Bem, se isso acontecesse, o rastreamento da pilha ficaria diferente. A primeira linha "at" diria que a exceção foi lançada em alguma linha da java.lang.Stringclasse e a linha 4 de Test.javaseria a segunda linha "at".

Então, de onde isso nullveio? Nesse caso, é óbvio e é óbvio o que precisamos fazer para corrigi-lo. (Atribua um valor não nulo a foo.)

OK, então vamos tentar um exemplo um pouco mais complicado. Isso exigirá alguma dedução lógica .

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

Então agora temos duas linhas "at". O primeiro é para esta linha:

return args[pos].length();

e o segundo é para esta linha:

int length = test(foo, 1);

Olhando para a primeira linha, como isso poderia gerar um NPE? Existem duas maneiras:

  • Se o valor de barfor null, bar[pos]lançará um NPE.
  • Se o valor de bar[pos]estiver nullchamando length(), lançará um NPE.

Em seguida, precisamos descobrir qual desses cenários explica o que realmente está acontecendo. Começaremos explorando o primeiro:

De onde barvem? É um parâmetro para a testchamada do método e, se observarmos como testfoi chamado, podemos ver que ele vem da foovariável estática. Além disso, podemos ver claramente que inicializamos foocom um valor não nulo. Isso é suficiente para ignorar provisoriamente essa explicação. (Em teoria, algo mais poderia mudar foo para null... mas isso não está acontecendo aqui.)

E o nosso segundo cenário? Bem, podemos ver que posé 1, então isso significa que foo[1]deve ser null. Isso é possível?

De fato é! E esse é o problema. Quando inicializamos assim:

private static String[] foo = new String[2];

alocamos a String[]com dois elementos inicializadosnull . Depois disso, não alteramos o conteúdo de foo... foo[1]ainda será null.


425

É como se você estivesse tentando acessar um objeto que é null. Considere o exemplo abaixo:

TypeA objA;

No momento, você acabou de declarar esse objeto, mas não foi inicializado ou instanciado . E sempre que você tentar acessar qualquer propriedade ou método nele, será lançado o NullPointerExceptionque faz sentido.

Veja também este exemplo abaixo:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

1
Se dermos System.out.println (a.length ()); // NullPointerException será lançado, para pular isso, podemos lidar com o bloco try try. obrigado
Vijaya Varma Lanke

359

Uma exceção de ponteiro nulo é lançada quando um aplicativo tenta usar nulo em um caso em que um objeto é necessário. Esses incluem:

  1. Chamando o método de instância de um nullobjeto.
  2. Acessando ou modificando o campo de um nullobjeto.
  3. Tomando o comprimento de nullcomo se fosse uma matriz.
  4. Acessando ou modificando os slots nullcomo se fosse uma matriz.
  5. Jogando nullcomo se fosse um valor jogável.

Os aplicativos devem lançar instâncias dessa classe para indicar outros usos ilegais do nullobjeto.

Referência: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


12
Mantenha-o simples, eu gosto desta resposta, adicione se você considerar correta - Acesso ao atributo não inicializado de um objeto
Emiliano

5
@Emiliano - simplesmente acessar um atributo inicializado não causa um NPE. É o que você >> faz com o valor do atributo não inicializado que causa o NPE.
Stephen C

1
Se você quiser mais casos: 1) usando a nullcomo o alvo de um synchronizedbloco, 2) usando a nullcomo o alvo de a switch, e unboxing null.
Stephen C

333

Um nullponteiro é aquele que aponta para lugar nenhum. Quando você desreferencia um ponteiro p, diz "me dê os dados no local armazenado em" p ". Quando pé um nullponteiro, o local armazenado pé nowhere, você está dizendo" me dê os dados no local 'em nenhum lugar' ". Obviamente, ele não pode fazer isso, então lança a null pointer exception.

Em geral, é porque algo não foi inicializado corretamente.


2
Estamos criando um banco de dados? -> NULLé escrito como nullem java. E é uma coisa sensível a maiúsculas e minúsculas.
bvdb

3
"Um ponteiro NULL é aquele que aponta para lugar nenhum" eu discordo. Ponteiros nulos não apontam para lugar nenhum, eles apontam para valores nulos.
TheRealChx101 8/08

2
@ TheRealChx101 Um ponteiro nulo e um ponteiro para um valor nulo são coisas diferentes - um ponteiro nulo não aponta para um valor nulo. Suponha que você tenha um ponteiro para um ponteiro: o ponteiro A aponta para o ponteiro B e o ponteiro B é nulo. Nesse caso, o ponteiro A aponta para um valor nulo e o ponteiro B é um ponteiro nulo.
MrZebra

321

Muitas explicações já estão presentes para explicar como isso acontece e como corrigi-lo, mas você também deve seguir as práticas recomendadas para evitar NullPointerExceptions.

Veja também: Uma boa lista de práticas recomendadas

Eu acrescentaria, muito importante, fazer um bom uso do finalmodificador. Usando o modificador "final" sempre que aplicável em Java

Resumo:

  1. Use o finalmodificador para impor uma boa inicialização.
  2. Evite retornar nulo nos métodos, por exemplo, retornar coleções vazias quando aplicável.
  3. Use anotações @NotNulle@Nullable
  4. Falha rapidamente e use asserts para evitar a propagação de objetos nulos por todo o aplicativo quando eles não devem ser nulos.
  5. Use iguais com um objeto conhecido primeiro: if("knownObject".equals(unknownObject)
  6. Prefere valueOf()mais toString().
  7. Use StringUtilsmétodos seguros nulos StringUtils.isEmpty(null).
  8. Use o Java 8 Optional como valor de retorno nos métodos. A classe Optional fornece uma solução para representar valores opcionais em vez de referências nulas.

4
Em projetos j2ee, a exceção Nullpointer é muito comum. Alguns casos referenciam variáveis ​​com valores nulos. Portanto, você deve verificar a inicialização da variável corretamente. = 0) {code ur que utiliza bandeira}
Amaresh Pattanayak

14
Vale ressaltar que alguns IDEs (por exemplo, Eclipse) oferecem análise automática de nulidade com base em anotações personalizáveis (por exemplo, @Nullableconforme listado acima) e alertam sobre possíveis erros. Também é possível inferir e gerar essas anotações (por exemplo, o IntelliJ pode fazer isso) com base na estrutura de código existente.
Jan Chimiak

4
A primeira coisa a fazer é antes de usar um objeto anulável, verifique se ele é nulo, usando if (obj==null). Se for nulo, você deve escrever um código para lidar com isso também.
Lakmal Vithanage

4
Na IMO, é preferível evitar o retorno de objetos nulos nos métodos quando possível e usar anotação quando parâmetros de entrada nulos não forem permitidos para, por contrato, reduzir a quantidade de 'se (obj == null)' no código e melhorar o legibilidade do código.
LG

4
Leia isto ... antes de aceitar essas "melhores práticas" como verdade: satisfice.com/blog/archives/27
Stephen C

316

Em Java, tudo (excluindo tipos primitivos) está na forma de uma classe.

Se você deseja usar qualquer objeto, então você tem duas fases:

  1. Declarar
  2. Inicialização

Exemplo:

  • Declaração: Object object;
  • Inicialização: object = new Object();

O mesmo para o conceito de matriz:

  • Declaração: Item item[] = new Item[5];
  • Inicialização: item[0] = new Item();

Se você não está fornecendo a seção de inicialização, então NullPointerExceptionsurge.


3
Uma NullPointerException geralmente ocorre ao chamar o método de uma instância. Por exemplo, se você declarar uma referência, mas não apontar para nenhuma instância, NullPointerException ocorrerá quando você chamar seu método. como: YourClass ref = null; // ou ref = anotherRef; // mas anotherRef não apontou nenhuma instância ref.someMethod (); // lançará NullPointerException. Geralmente, corrija-o desta maneira: Antes de o método ser chamado, determine se a referência é nula. como: if (yourRef! = null) {yourRef.someMethod (); }
sunhang

2
Ou use a captura de exceção: como: try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang 28/07


315

Uma exceção de ponteiro nulo é um indicador de que você está usando um objeto sem inicializá-lo.

Por exemplo, abaixo está uma turma de alunos que a utilizará em nosso código.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

O código abaixo fornece uma exceção de ponteiro nulo.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Porque você está usando student, mas esqueceu de inicializá-lo como no código correto mostrado abaixo:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

7
Embora este seja um bom exemplo, posso perguntar o que isso acrescenta à pergunta que ainda não está coberta por todas as outras respostas?
Mysticial

13
É simplesmente inapropriado usar a palavra "não inicializado" aqui. O exemplo que você mostrou é de fato "inicializado" e inicializado com nulo. Para variáveis ​​não inicializadas, o compilador irá reclamar com você.
Adrian Shum

2
Um NPE pode ser um indicador de que você está usando um campo não inicializado. Pode ser um indicador de que você está fazendo outras coisas. Simplificar demais para uma causa única como essa não ajuda alguém a resolver problemas de NPE ... se a causa real não for essa.
Stephen C

309

Em Java, todas as variáveis ​​que você declara são na verdade "referências" aos objetos (ou primitivas) e não aos objetos em si.

Quando você tenta executar um método de objeto, a referência solicita que o objeto ativo execute esse método. Mas se a referência estiver fazendo referência a NULL (nada, zero, vazio, nada), não há como o método ser executado. Em seguida, o tempo de execução permite que você saiba disso lançando uma NullPointerException.

Sua referência é "apontando" para nulo, portanto "Nulo -> Ponteiro".

O objeto reside no espaço de memória da VM e a única maneira de acessá-lo é usando thisreferências. Veja este exemplo:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

E em outro lugar no seu código:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Isso é uma coisa importante a saber - quando não houver mais referências a um objeto (no exemplo acima, quando referencee otherReferenceambos apontarem para nulo), o objeto estará "inacessível". Não há como trabalhar com ele; portanto, esse objeto está pronto para ser coletado como lixo e, em algum momento, a VM liberará a memória usada por esse objeto e alocará outro.


280

Outra ocorrência de a NullPointerExceptionocorre quando alguém declara uma matriz de objetos e tenta imediatamente desreferenciar elementos dentro dela.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Esse NPE em particular pode ser evitado se a ordem de comparação for revertida; ou seja, use .equalsem um objeto não nulo garantido.

Todos os elementos dentro de uma matriz são inicializados com seu valor inicial comum ; para qualquer tipo de matriz de objetos, isso significa que todos os elementos são null.

Você deve inicializar os elementos na matriz antes de acessá-los ou desreferenciá-los.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

A operação no objeto não inicializado no nível da instância (não no nível da classe) levará a NullPointerException. A operação precisa ser específica da instância. se a operação estiver no nível da classe, dizendo que chamar um método estático no objeto não inicializado, ele não lançará a exceção NullPointerException. Até os objetos da classe wrapper primitiva lançam NullPointerException.
Shailendra Singh

1. NullPointerException é uma RuntimeException, o que significa que aparecerá quando o programa estiver em execução e você não fará a compilação. :(, mas a maioria do IDE ajuda você a descobrir isso. 2. Minimize o uso da palavra-chave 'null' nas instruções de atribuição. :) URL de referência:
tomj0101

@ tomj0101 Não sei ao certo por que você fez esse comentário ... Mas, para o seu segundo ponto, um padrão anterior Optionalera retornar nulo. A palavra-chave está correta. Saber se proteger contra isso é fundamental. Isso oferece uma ocorrência comum e maneiras de mitigá-lo.
Makoto

NullPointerException é uma exceção em tempo de execução que não é recomendada para capturá-lo, mas evita-o.
Shomu

2
@Shomu: Até que ponto eu sugiro que seja pego?
Makoto
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.