Melhor pratica para Nullpointer

32 respostas
F

Olá pessoal, tenho uma aplicação que em determinado momento é mostrado o codigo do ibge de um estado para um determinado endereço.
Para pegar ele é feito dessa maneira.

endereco.getRua().getCidade().getCodigoIbge()

Esse código nesse caso não é obrigatório, e devo mostrar em branco minha duvida é qual a melhor pratica para isso.

Sei que posso tratar de 2 maneira com um try cacth ou encadear varios ifs

public String getCodMunicipio() {
		try {
			return endereco.getRua().getCidade().getCodigoIbge().toString();
		} catch (NullPointerException e) {
			return "";
		}
	}
public String getCodMunicipio() {
                if(endereco == null){
			return "";
		}else if(endereco.getCidade()==null){
			return "";			
		}else if(endereco.getCidade().getCodigoIbge()==null){
			return "";
		}else{
			enderecogetCidade().getCodigoIbge().toString();
		}	
        }

32 Respostas

Hebert_Coelho

Prefiro o primeiro. [=

marciobarroso

eu tb

pmlm
public String getCodMunicipio() {  
     if(endereco != null && endereco.getRua() != null && endereco.getRua().getCidade() != null && endereco.getRua().getCidade().getCodigoIbge() != null)
         return endereco.getRua().getCidade().getCodigoIbge().toString();  
    }
    return ""; 
}
igor_ks

também sou mais o segundo

muito melhor validar algo antes, do que esperar um NullPointer
nao é feio isso? esperar um nullpointer, estranho…

Hebert_Coelho

igor_ks:
também sou mais o segundo

muito melhor validar algo antes, do que esperar um NullPointer
nao é feio isso? esperar um nullpointer, estranho…

Por mim, não retornaria null em nenhum método. Todos os gets verificariam se é null, e retornam “”. Mas fui dentro da proposta dele. [=

renanreismartins

o duro de tratar uma nullPointer como no 1o caso, é que nunca sabemos onde ela está acontecendo, se é no getRua, getCidade e etc, mas dependendo do contexto é aceitável.

Boas práticas dizem que não devemos retornar null e sim um objeto em condições “especiais”, um exemplo clássico disso é retornar listas vazias ao invés de null, porém, não sei até onde isso se aplica. Por exemplo, talvez retornar um objeto cidade com tds atributos em branco.

abrasss

igor_ks

Sim, a primeira vez que cliquei em “Responder” ia falar isso, “O melhor é nunca ter a necessidade de verificar se o campo está nulo”. Mas ai pensei que talvez estaria sendo grosseiro, e respondi conforme foi a pergunta dele e as respostas que li tb

F

Hebert Coelho:
igor_ks:
também sou mais o segundo

muito melhor validar algo antes, do que esperar um NullPointer
nao é feio isso? esperar um nullpointer, estranho…

Por mim, não retornaria null em nenhum método. Todos os gets verificariam se é null, e retornam “”. Mas fui dentro da proposta dele. [=

o getCidade não tem como retornar “” pois ele retorna um objeto do tipo cidade.

Eu teria mesmo que validar todos os niveis da hierarquia até chegar ao CodigoIbge

F

renanreismartins:
o duro de tratar uma nullPointer como no 1o caso, é que nunca sabemos onde ela está acontecendo, se é no getRua, getCidade e etc, mas dependendo do contexto é aceitável.

Boas práticas dizem que não devemos retornar null e sim um objeto em condições “especiais”, um exemplo clássico disso é retornar listas vazias ao invés de null, porém, não sei até onde isso se aplica. Por exemplo, talvez retornar um objeto cidade com tds atributos em branco.

abrasss

me indicaria algum livro sobre boas práticas?

renanreismartins

sim, pra esse assunto oque mais gostei foi clean code do kent beck, vai te ajudar mto

abrasss

F

renanreismartins:
o duro de tratar uma nullPointer como no 1o caso, é que nunca sabemos onde ela está acontecendo, se é no getRua, getCidade e etc, mas dependendo do contexto é aceitável.

Boas práticas dizem que não devemos retornar null e sim um objeto em condições “especiais”, um exemplo clássico disso é retornar listas vazias ao invés de null, porém, não sei até onde isso se aplica. Por exemplo, talvez retornar um objeto cidade com tds atributos em branco.

abrasss

Nessa applicação tenho diversos cadastro de pessoas diferentes … fornecedores … clientes … usuarios etc.

Em clientes e somente em clientes o atributo cidade é Obrigadorio… nessa pratica eu teria no meu Controller fazer a validação do campo Cidade se retorno getCidade null posso fazer o if

if( pessoa.getcidade() == null){
//error
}

se retornar um objeto cidade com atributos em branco teria que fazer algo tipo

if( pessoa.getcidade() != new Cidade("","", null) ){
//error
}

Não fica estranho!!

renanreismartins

assim ficaria realmente muito ruim, então vc poderia verificar por id. Mas ai não diferencia da verificação apenas por null. Por isso falei que precisava consultar se nesse tipo de objetos seria interessante retornar uma instancia “especial” entendeu?

UPDATE: uma discussão interessante que achei no stackoverflow, essa resposta me parece a melhor:

fonte: http://stackoverflow.com/questions/1626597/should-functions-return-null-or-an-empty-object

abrasss

F

renanreismartins:
assim ficaria realmente muito ruim, então vc poderia verificar por id. Mas ai não diferencia da verificação apenas por null. Por isso falei que precisava consultar se nesse tipo de objetos seria interessante retornar uma instancia “especial” entendeu?

UPDATE: uma discussão interessante que achei no stackoverflow, essa resposta me parece a melhor:

fonte: http://stackoverflow.com/questions/1626597/should-functions-return-null-or-an-empty-object

abrasss

Não teria algum exemplo.

Hebert_Coelho

fernandoat:
Hebert Coelho:
igor_ks:
também sou mais o segundo

muito melhor validar algo antes, do que esperar um NullPointer
nao é feio isso? esperar um nullpointer, estranho…

Por mim, não retornaria null em nenhum método. Todos os gets verificariam se é null, e retornam “”. Mas fui dentro da proposta dele. [=

o getCidade não tem como retornar “” pois ele retorna um objeto do tipo cidade.

Eu teria mesmo que validar todos os niveis da hierarquia até chegar ao CodigoIbge

Retorne um objeto novo então.

F

Hebert Coelho:
fernandoat:
Hebert Coelho:
igor_ks:
também sou mais o segundo

muito melhor validar algo antes, do que esperar um NullPointer
nao é feio isso? esperar um nullpointer, estranho…

Por mim, não retornaria null em nenhum método. Todos os gets verificariam se é null, e retornam “”. Mas fui dentro da proposta dele. [=

o getCidade não tem como retornar “” pois ele retorna um objeto do tipo cidade.

Eu teria mesmo que validar todos os niveis da hierarquia até chegar ao CodigoIbge

Retorne um objeto novo então.

Em outro momento nessa applicação tenho cadastro cliente.

Em cliente e somente em cliente o atributo cidade é Obrigadorio… nessa pratica eu teria no meu Controller fazer a validação do campo Cidade se retorno getCidade null posso fazer o if

if(pessoa.getEndereco.getCidade()== new Cidade()){
//error
}

Não acha que fica estranho?

gomesrod

O primeiro jeito é mais fácil de digitar.
O segundo é mais “certo”. A NullPointerException representa um erro de programação, ela não deve fazer parte do fluxo normal de um programa. Imagine se um dia você precisar fazer uma pequena lógica em um desses gets, se ele tiver um erro e der nullpointer você vai ter resultados incorretos sem nunca detectar o erro!

Para mim a melhor solução é essa aqui, que é robusta e não precisa digitar tanto quanto a opção dos vários IFs:

pmlm:
public String getCodMunicipio() { if(endereco != null && endereco.getRua() != null && endereco.getRua().getCidade() != null && endereco.getRua().getCidade().getCodigoIbge() != null) return endereco.getRua().getCidade().getCodigoIbge().toString(); } return ""; }

E você ainda pode desenvolver mais a idéia:

endereco.getRua().getCidade().getCodigoIbge()

Procure saber, segundo as regras de negócio, exatamente quais desses atributos podem estar nulos. Por exemplo, o endereço pode estar nulo, Ok. Mas se tiver um endereço será que é realmente opcional ter a Rua ? E se eu tiver a Cidade, faz sentido na regra de negócio que não tenha o Código IBGE?

Dessa maneira você testa só o que é esperado. Se alguma coisa diferente estiver nula, então é erro de aplicação mesmo e o mais correto é deixar a exceção estourar.

renanreismartins

EXCELENTE gomesrod!

fernando n tem mto o q exemplificar, segundo o cara do stackoverflow o lance é: NESTE CASO retornar nulo mesmo quando seu dado realmente não existe, concordo com ele, faz mais sentido.

agora o gomes deu uma excelente forma de melhorar a legibilidade do seu código.

abrassss

F

gomesrod:
O primeiro jeito é mais fácil de digitar.
O segundo é mais “certo”. A NullPointerException representa um erro de programação, ela não deve fazer parte do fluxo normal de um programa. Imagine se um dia você precisar fazer uma pequena lógica em um desses gets, se ele tiver um erro e der nullpointer você vai ter resultados incorretos sem nunca detectar o erro!

Para mim a melhor solução é essa aqui, que é robusta e não precisa digitar tanto quanto a opção dos vários IFs:

pmlm:
public String getCodMunicipio() { if(endereco != null && endereco.getRua() != null && endereco.getRua().getCidade() != null && endereco.getRua().getCidade().getCodigoIbge() != null) return endereco.getRua().getCidade().getCodigoIbge().toString(); } return ""; }

E você ainda pode desenvolver mais a idéia:

endereco.getRua().getCidade().getCodigoIbge()

Procure saber, segundo as regras de negócio, exatamente quais desses atributos podem estar nulos. Por exemplo, o endereço pode estar nulo, Ok. Mas se tiver um endereço será que é realmente opcional ter a Rua ? E se eu tiver a Cidade, faz sentido na regra de negócio que não tenha o Código IBGE?

Dessa maneira você testa só o que é esperado. Se alguma coisa diferente estiver nula, então é erro de aplicação mesmo e o mais correto é deixar a exceção estourar.

OMG realmente não tinha pensado, facilita quando se tem uma regra de negócios definida e nesse caso eu tenho só terei que validar se o endereço é null o restante quando há um endereço é obrigatório

Obrigado a todos.

gomesrod

Só lembrando que eu fiz quote de uma sugestão que deram lá na primeira página no tópico, tinha passado despercebida na discussão. Acho que porque era um post pequenininho rs

Agora sim o cenário ideal… checar tudo faria parecer que está “fugindo” de analisar cuidadosamente a situação, assim fica mais bem definido.

R

bom... lógico que da pra evitar tantas verificações mexendo nisso antes... mas dentro desse contexto que ele passou, eu deixaria assim:

public String getCodMunicipio() {  
    
    String ibge = "";

    try {  
        ibge = endereco.getRua().getCidade().getCodigoIbge().toString();  
    } catch (NullPointerException e) {  
       // tratamento de erro comum
    }  

    return ibge;
}

parece mesma coisa que ele passou mas o jeito que fiz evita tratar de códigos dentro do catch... que não é considerado boa prática... catch geramente só usamos pra capturar o erro

sergiotaborda

fernandoat:
Olá pessoal, tenho uma aplicação que em determinado momento é mostrado o codigo do ibge de um estado para um determinado endereço.
Para pegar ele é feito dessa maneira.

endereco.getRua().getCidade().getCodigoIbge()

Esse código nesse caso não é obrigatório, e devo mostrar em branco minha duvida é qual a melhor pratica para isso.

Isto é uma clara e óbiva violação da Lei de Demeter que já foi conversado ainda ha pouco tempo aqui

O que está errado não o nullpointer, é a chamada telescopica.

A opção de usar exception não é aceitável. Exceções não servem como substituto de ifs. É uma má prática se vc fizer isso.

Existe a opção de criar um Maybe (Option em outras linguagens) como é usado no Google Guava.

Existe a opção de criar um Utils que sabe interpretar e navegar nessa estrutrua protegendo de nulls.

Mas eu ainda acho que o melhor é isto

class Endereco(){


    public String getCodigoIBGE(){
        return this.rua == null ? null : this;rua.getCodigoIBGE();
}

}

Repare como o endereço delega à rua, que delegaria à ciddade, etc…
Para isto vc tem que ter acesso às classes. Se tem, este é o jeito correto de evitar a chamada telescopica e respeita a lei de demeter.

Se não tem acesso à classe, faça com métodos (que podem staticos num utis da vida ou private na classe que está tentando ler o codigo)

public String getCodigoIBGE(Endereço endereco){

            if (endereco.getRua () != null ){

                      return getCodigoIBGE(endereco.getRua());
           }

           return null;
}

public String getCodigoIBGE(Rua rua){

            if (endereco.getcCdade() != null ){

                      return getCodigoIBGE(endereco.getcCdade());
           }

           return null;
}

Em Resumo, faça leitura recursiva controlando em cada ponto o null. Se vc ainda quer uma mensagem, em vez de retornar null, vc pode lançar um exception. E se lançar exception , ai sim, pode usar a primeira construção que colocou. mas nunca jamais faça catch de NullpointerException.

pmlm

Muitas vezes parece que sou invisivel neste forum… Já deixei de tentar perceber porquê… :smiley:

renanreismartins

oi pmim, boa haahahaah

eu vi rapidamente sua solução, porém, só consegui enxergar a ideia com a explicação do gomes, falando q poderiamos evitar alguns ifs, perdão man! vc n eh invisivel já vi varios topicos seus q me ajudaram

abrassss

fredericomaia10

Dá uma olhada no Introduce Null Object. http://sourcemaking.com/refactoring/introduce-null-object

Parece um trabalho grande mesmo esta prática, nunca experimentei mas pode ser que fique legal o resultado.

Este site em geral tem um conteúdo muito bom sobre Refactoring e Patterns.

johnny_quest

Como já foi falado acima, isso é uma má prática…
De acordo com o Effective Java, Unchecked exceptions NÃO devem ser tratadas via try catch…

RuntimeExceptions são erros de programação e não são recuperáveis, se lançar NullPointer o programa deve parar, e não ser recuperado retornado string vazia.

Para evitar tal estado, poderia criar um método a parte para validar se o objeto está em estado consistente
e somente depois fazer a chamada ao método desejado. Igual ao se fazer a chamada à algum Iterator…

if(it.hasNext()) { objetc = it.next(); }

maior_abandonado

pessoalmente eu acho que não é legal mesmo você usar exceção “como se fosse um if”, mas em certos casos eu ainda acho que fica melhor… esse provavelmente é um destes. Considero melhor por que com a exceção, primeiro que o código fica mais fácil de ler, bater o olho e entender ele, segundo pro que ele ficará mais rápido na maioria dos casos, pense bem, na maioria dos casos espera-se este campo não esteja nulo, sendo assim ao invés de ficar fazendo um monte de comparação já o pega direto e o usa.

mesmo nos casos onde estiver nulo, la por exemplo nos últimos itens, precisaria do teste más desconfio que o lançamento da exceção seja mais rápido que a verificação a partir da terceira, sei la…

um ultimo comentário, se isso for utilizado em mais lugares, a lei de demeter torna-se mais interessante, então isso ficaria no endereço…

sei que isso vai contra certos princípios de códigos bem escritos, mas acho que me baseei nos motivos destes princípios (legibilidade de código, se usada a lei de demeter reaproveitamento e quando for importante, performance).

claro que isso é opinião, se eu estiver errado em algum ponto aceito criticas construtivas.

gomesrod

Já que a discussão está tocando nesse ponto de “as exceções devem ou não fazer parte do fluxo normal de decisão de um programa ?”.

Só existe na história desse País uma situação onde a checagem deve ser feita usando exceção. E é por uma deficiência na API, não porque é bonito.
Esse caso é quando se quer verificar se uma string é um número ou data válida. Não existe na API um método que faça essas checagens.

Por exemplo:

boolean isValidNumber(String s) { NumberFormat nf = ... // Inicializa e seta os atributos conforme o formato desejado try { nf.parse(s); return true; //Sucesso no parse } catch (NumberFormatException nfe) { return false; } }

Poderia varrer a String e fazer a checagem, dependendo do caso isso é simples (por exemplo se a String precisa ser exclusivamente numérica), mas também pode ficar complexo, com sinais de +/-, decimais, agrupamento, notação em potência de 10, etc.

O mesmo com datas, é possível verificar a formatação básica com uma regex, mas aí tem todo o trabalho de ver se o dia é válido naquele mês, se é bissexto, lidar com formatos diferentes, etc.


Para todos os outros casos, devemos testar ANTES de chamar a operação que pode causar exceção. Se der exceção no ponto onde minha checagem não esperava então ótimo, acabamos de pegar um bug :slight_smile:

sergiotaborda

maior_abandonado:
pessoalmente eu acho que não é legal mesmo você usar exceção “como se fosse um if”, mas em certos casos eu ainda acho que fica melhor… esse provavelmente é um destes. Considero melhor por que com a exceção, primeiro que o código fica mais fácil de ler, bater o olho e entender ele, segundo pro que ele ficará mais rápido na maioria dos casos, pense bem, na maioria dos casos espera-se este campo não esteja nulo, sendo assim ao invés de ficar fazendo um monte de comparação já o pega direto e o usa.

mesmo nos casos onde estiver nulo, la por exemplo nos últimos itens, precisaria do teste más desconfio que o lançamento da exceção seja mais rápido que a verificação a partir da terceira, sei la…

um ultimo comentário, se isso for utilizado em mais lugares, a lei de demeter torna-se mais interessante, então isso ficaria no endereço…

sei que isso vai contra certos princípios de códigos bem escritos, mas acho que me baseei nos motivos destes princípios (legibilidade de código, se usada a lei de demeter reaproveitamento e quando for importante, performance).

claro que isso é opinião, se eu estiver errado em algum ponto aceito criticas construtivas.

Existe um ranking de práticas, ou seja, algumas são melhores que outras. Então tempos, más práticas, práticas, boas práticas e melhores práticas.
As melhores práticas dizem que vc não deve usar try-catch para tratar nullpointer. A razão disso não é legibilidade, é que pode mascarar outros defeitos que não aquele que vc acha que vai acontecer e ai seu programa vai começar a funcionar errado, mas parecendo que funciona certo. No exemplo em estudo, se o endereço em si for null temos a mesma execeção. Mas se o endereço em si for null o erro está em outra parte do sistema que não está lendo ele direito. Mas o que vc vai ver é nenhum erro e nenhum odigo IBGE nunca. Isto é um bug mais complicado de avaliar, e pela simples razão que fez catch de nullpointer.

Existem razões lógicas e até matemáticas por baixo das melhores práticas. Não é apenas um agregado de ideias avulsas. A legibilidade também é um boa prática, mas neste caso o que vc chama de “legebilidade” signiica “escrever menos”. Escrever menos não é uma boa prática em si mesmo e não é razão que justifique coisa alguma. Legibilidade é “eu entendo o que leio”. O programador que ler o catch não vai entender porque o nullpointer está sendo capturado sem um coment que explique. Portanto, não está ajudando à legibilidade coisa nenhuma.

É comum este sentimento de “posso violar as melhores práticas se houver um boa razão” e isso é verdade, o problema é que as razões que são dadas são normalmente más.
A lei de demeter é sempre importante , como todos os principios em geral. dizer que existe uma ocasião quando ela não é importante é como dizer que às vezes a gravidade não atrai os objetos.

Vejam assim, estes princípios são forças internas ao design OO e elas operam , ou deveriam operar, para chegar num melhor modelo. Mas tem as forças externas que também operam sobre o sistema e impedem o modelo de ser o melhor que poderia. Estas forças externas são várias como custo e tempo mas temos também a indulgência do programador em achar que a sua razão é boa o suficiente para contrariar os princípios. E este é o real problema. Porque é de certa forma subjetivo e artificial. ( ou contrario do custo e do tempo que são reais ).

Então, a menos que a gente goste de apostar o design dos sistema na nossa indulgência é melhor não violar os principios. É para isso que eles foram reunidos.

marciobarroso

Ao meu ver, se você utilizar o primeiro formato seria correto criar uma exceção para essa regra. Assim, caso ocorra o nullpointerexception, ao invés de você simplesmente receber um nullpointer sem muita informação no stack, você receberia uma exceção criada por você que seria facilmente identificada.

Não acho que o NullPointerException deve ser encarado somente como erro do programador. Muitas outras ocasiões condizem com esta condição e não precisa necessariamente ser um erro de programação.

Eu normalmente trato tudo com exceções e no ultima camada da aplicação, eu dou o tratamento adequado para cada exceção.

Pode não existir “a forma ideal” de se fazer tal coisa em java ou qq outra linguagem. Acho que a vivencia e experiencia de cada um acaba fazendo com que você chegue ao melhor modelo.

Já li aqui no fórum um tutorial, se não me engano escrito pelo CV, que trata de forma clara o tratamento de exceções. Acho que vale a pena dar uma olhada e talvez chegar a uma conclusão própria.

Boa sorte =)

victormagno

Ótimos argumentos, sergiotaborda. Concordo plenamente.

Andre_Fonseca

Sobre exceptions tem um tutorial muito bom aqui

Sobre o NullPointer eu acho que já falaram bastante, eu também acho uma boa tratar diretamente nos Beans, um bom uso para anotações

aqui ou aqui podemos encontrar ajuda…

Sobre boas práticas, más práticas, acho que muitas acabam mudando com o tempo conforme a tecnologia vai mudando, hoje em dia não devemos (pelo menos não deveríamos) considerar mais o uso de Scriptlets em JSP’s, infelizmente é o que eu mais vejo por ai… rs

Hebert_Coelho

André Fonseca:
Sobre exceptions tem um tutorial muito bom aqui

Sobre o NullPointer eu acho que já falaram bastante, eu também acho uma boa tratar diretamente nos Beans, um bom uso para anotações

aqui ou aqui podemos encontrar ajuda…

Sobre boas práticas, más práticas, acho que muitas acabam mudando com o tempo conforme a tecnologia vai mudando, hoje em dia não devemos (pelo menos não deveríamos) considerar mais o uso de Scriptlets em JSP’s, infelizmente é o que eu mais vejo por ai… rs

uhum.

Se não me engano o java 7 já tem até uma saída que seria algo como: cidade.getEstado?().getNome().

Criado 10 de janeiro de 2013
Ultima resposta 11 de jan. de 2013
Respostas 32
Participantes 14