Programação Defensiva e o NullPointerException

54 respostas
L

Olá, pessoal. Queria discutir aqui sobre uma situação muito corriqueira em qualquer programação, que é a tentativa de manipular uma referência nula.
Quem nunca tomou um NullPointerException na cara?? Pois é, justamente por ser algo muito comum, acho que é bem importante nos atentarmos sobre como lidar com essas situações.
Suponha um método qualquer que recebe um objeto qualquer como paramêtro e faz algo com ele. Por exemplo:

public void algumaCoisa(Qualquer o) { o.metodo(); }
Algo realmente simples, que temos aos montes em qualquer projeto. Infelizmente, é possível que esse método receba null como parâmetro e, quando isso ocorrer, o maldito vai aparacer na hora! Claro que seria uma “burrice evitável” alguém chamar o método algumaCoisa passando null explicitamente como parâmetro, mas lembrem-se que a passagem de parâmetro pode ser dinâmica, e aí o erro fica mais difícil de detectar…

Qualquer q = null;
    // Aqui tem um código que tenta setar a variável q, mas pode não conseguir.
    algumaCoisa(q);

Existe alguma regra geral de programação defensiva? Em cada método que criarmos devemos checar nossos parâmetros? Ou jamais devemos setar variáveis com null? O que vocês acham dessa situação?

54 Respostas

W

http://www.fragmental.com.br/wiki/index.php/Contratos_Nulos

L

Uma outra situação igualmente comum e perigosa é a seguinte:
Um método tipo get que retorna um tipo específico pode simplesmente retornar o valor null. Essa possibilidade, se passar despercebida por quem invocar o método, vai levar a um NullPointer na hora. Exemplo:

public Ball getBall(int id) { Ball retorno = null; retorno = BallDAO.recuperaBola(id); // Se não existir bola com esse id no banco, recuperaBola(int) retorna null. return retorno; }
E aí? É melhor retornar uma bola vazia do que null? Ou é melhor ainda sempre levantarmos uma exceção nessas horas?
Comos vocês fazem?

W

Nenhum dos dois… Leia o link que eu te passei… Vai responder todas essas questões…

[]´s

V

No link ele fala disso aqui:

public void doSomething(String a) {
   a.split();
}

Nesse caso, realmente, é inútil testar se a é ou não nulo, pois o nullpointerexception e a exceção farão a mesma coisa. Mas nesse caso, não:

public void setA(String a) {
    if (a == null) throw new IllegalArgumentException("A is null!");

    this.a = a;
}

A diferença aqui é que o atributo a, do this, também irá conter o valor nulo. A exceção não ocorrerá nesse método, e sim na hora que outro método que depende de A for usado. Sem essa verificação, teremos muito mais dificuldade de chegar a origem do problema quando a exceção ocorrer.

O resto da página é realmente ótima. Eu acho a abordagem comentada um pouco purista demais, mas uma coisa é fato:
É muito importante pensarmos no contrato das classes, método por método.

W
ViniGodoy:
No link ele fala disso aqui:
public void doSomething(String a) {
   a.split();
}

Nesse caso, realmente, é inútil testar se a é ou não nulo, pois o nullpointerexception e a exceção farão a mesma coisa. Mas nesse caso, não:

public void setA(String a) {
    if (a == null) throw new IllegalArgumentException("A is null!");

    this.a = a;
}

A diferença aqui é que o atributo a, do this, também irá conter o valor nulo. A exceção não ocorrerá nesse método, e sim na hora que outro método que depende de A for usado. Sem essa verificação, teremos muito mais dificuldade de chegar a origem do problema.

O resto da página é realmente ótima.

Aparentemente você não leu o texto por completo. Vou reproduzir abaixo a parte que você mencionou:

O grande problema é que geralmente as pessoas fazem assim:
public static void fazerAlgo(String a){
 if(a==null) throw IssoNaoEhUmaNullPointerExceptionException("a deve ser definido");
  
 a.split(" ");
}

Ou seja: fazem a mesma coisa que uma NPE faz, mas usando IllegalArgumentException ou outra exceção qualquer.

E é sempre bom manter o estado do seu objeto válido, certo? Se você possui um atributo nulo, onde ele não deveria ser nulo, o erro é seu, e não de quem invoca o método...

L

Li o texto todo e, me corrija se eu estiver errado, ele prega que não devemos hesitar em abusar do uso de exceções.
Acho que o trecho que resume isso é o seguinte:
[i]“Quase sempre (na prática, diria que sempre) é melhor você interromper o processamento com uma exceção do que retornar um valor que não cumpre a pós-condição.”[/i]
Eu concordo que sempre fazer as checagens (respeitar o contrato) e usar as exceções é a forma mais robusta. Exceções servem justamente para lidarmos com esse tipo de situação, resultados inesperados, ERROS.
O que eu questiono é se vale a pena tomar isso como regra geral. Veja que os exemplos que eu citei são MUITO comuns. Fazer checagens de parâmetros o tempo todo, por exemplo, pode ser algo bem desgastante e, além disso, acredito que grande parte (senão a maioria) dos nosso métodos vai ter pelo menos uma cláusula throws. Será que vale a pena?

Acho que não tem muito o que discutir né… Como o bom senso é algo bem subjetivo, você tem que optar mesmo entre ter algo realmente robusto ou confiar nos clientes das suas classes…

V

E métodos private, eu geralmente prefiro usar asserções. Tem menos boilerplate e são muito menos desgastantes e desempenham o mesmo papel. Fora que, o tempo de execução delas é eliminado em runtime.

L

Será que é viajar demais se eu pensar que seria melhor que Java não permitisse passar valores nulos como parâmetros e, além disso, não permitisse que um método que deve retornar algum tipo qualquer retorne null?
Enfim, será que seria bom que referências a objetos fossem tratadas assim como os tipos primitivos nessas situações?
Verificar se uma referência qualquer pode não ter sido inicializada sempre pode ser feito em tempo de compilação.

Afinal, Java abstraiu a noção de ponteiros, embora tenha permanecido o maior perigo deles: Referências inválidas. Não acho logicamente limpo eu passar um valor nulo para um parâmetro que aceita um tipo específico como argumento. A referência nula não pode ser de quase todos os tipos que existem ao mesmo tempo! Percebam que só os tipos primitivos escapam disso. Por exemplo, não posso passar um parâmetro nulo para um método que recebe int! Não deveria ser feito o mesmo para os tipos criados? Isso abstrairia de vez a noção de ponteiros…

L

Claro que poderia ser feito algum tipo de palavra-chave que pudesse abrir explicitamente essa possibilidade, forçando o programador a levar em conta essa possibilidade.
Por exemplo, alguns atributos das classes muitas vezes não precisam assumir um valor padrão, inicializam-se vazias.
Acho que o importante é cercar em tempo de compilação as possibilidades desse tipo de erro. Será que é viajar demais? Seria um mundo muito melhor :smiley:

P

leandrocm86:
Será que é viajar demais se eu pensar que seria melhor que Java não permitisse passar valores nulos como parâmetros e, além disso, não permitisse que um método que deve retornar algum tipo qualquer retorne null?
Enfim, será que seria bom que referências a objetos fossem tratadas assim como os tipos primitivos nessas situações?
Verificar se uma referência qualquer pode não ter sido inicializada sempre pode ser feito em tempo de compilação.

Afinal, Java abstraiu a noção de ponteiros, embora tenha permanecido o maior perigo deles: Referências inválidas. Não acho logicamente limpo eu passar um valor nulo para um parâmetro que aceita um tipo específico como argumento. A referência nula não pode ser de quase todos os tipos que existem ao mesmo tempo! Percebam que só os tipos primitivos escapam disso. Por exemplo, não posso passar um parâmetro nulo para um método que recebe int! Não deveria ser feito o mesmo para os tipos criados? Isso abstrairia de vez a noção de ponteiros…

Ai vc estaria escondendo o sol com a peneira.

Os efeitos desastrosos de um NullPointerException são evitados com estes unitarios, respeito a contrato e patterns adequados como Null Object (eleger um objeto para ser o “null” daquela classe).

G

Eu tenho um projeto (que uso como biblioteca) que evita NullPointerExceptions em classes com atributos encapsulados… (GET e SET)

Afinal ficar escrevendo a mesma coisa pra todos os atributos é um saco. Acredito que hoje a tarde eu irei criar um tópico para mostrar a minha idéia e tb irei disponibilizar os fontes…

[]'s

V

As referências do C++ não permitem o null.

Agora, não creio que esse problema seja tão grave assim para merecer tanta preocupação. O java eliminou a parte grave: dangling pointers não existem na linguagem.

L

ViniGodoy:
As referências do C++ não permitem o null.

Agora, não creio que esse problema seja tão grave assim para merecer tanta preocupação. O java eliminou a parte grave: dangling pointers não existem na linguagem.


As referências de C++ não permitem null? Tem muito tempo que não programo em C++, mas não lembro disso.
Pelo contrário, lembro que o erro mais frequente lá era o Segmentation Fault, que seria uma espécie de avô do NullPointerException.
De qualquer forma, acho que isso gera problema suficiente para ser chamado de grave, basta ver a frequência com que ocorre. Seria uma coisa a melhorar, na minha muito humilde opinião.
Talvez em ambientes muito profissionais com projetos de altíssima qualidade isso realmente não seja um problema grande, mas eu com meu limitado conhecimento não vejo nenhuma outra coisa em Java que possa ser uma fonte maior de erros.

W

leandrocm86:
ViniGodoy:
As referências do C++ não permitem o null.

Agora, não creio que esse problema seja tão grave assim para merecer tanta preocupação. O java eliminou a parte grave: dangling pointers não existem na linguagem.


As referências de C++ não permitem null? Tem muito tempo que não programo em C++, mas não lembro disso.
Pelo contrário, lembro que o erro mais frequente lá era o Segmentation Fault, que seria uma espécie de avô do NullPointerException.
De qualquer forma, acho que isso gera problema suficiente para ser chamado de grave, basta ver a frequência em que ocorre. Seria uma coisa a melhorar, na minha muito humilde opinião.
Talvez em ambientes muito profissionais com projetos de altíssima qualidade isso realmente não seja um problema grande, mas eu com meu limitado conhecimento não vejo nenhuma outra coisa em Java que possa ser uma fonte maior de erros.

Segmentation Fault é erro de acesso a uma localidade de memória que vc não tem permissão de acesso… Esse erro ocorre normalmente quando não se aloca espaço correto para um objeto…

E é verdade que C++ não permite referência null, um ponteiro ‘null’ aponta para o endereço de memória 0.

L

Então… sei que já tá meio fugindo do escopo do assunto, mas agora fiquei curioso… rsrs
Compilei sem problemas o seguinte código em C++, usando Cygwin (com g++).

class Aluno
{
	private:
	int matricula;
	
	public:
	int getMatricula()
	{
		return matricula;
	}
};

int main()
{
	Aluno *a = 0;
	cout << a -> getMatricula() << endl;
	return 0;
}

Ele compila sem problema nenhum. Assim como Java, o erro só apareceu em tempo de execução, por tentar chamar um método através de um apontador nulo. Por sinal, foi um Segmentation Fault. Se o código acima fosse traduzido para Java, ocorreria a mesma coisa, só que com um NullPointerException, não?

W

leandrocm86:
Então… sei que já tá meio fugindo do escopo do assunto, mas agora fiquei curioso… rsrs
Compilei sem problemas o seguinte código em C++, usando Cygwin (com g++).

class Aluno
{
	private:
	int matricula;
	
	public:
	int getMatricula()
	{
		return matricula;
	}
};

int main()
{
	Aluno *a = 0;
	cout << a -> getMatricula() << endl;
	return 0;
}

Ele compila sem problema nenhum. Assim como Java, o erro só apareceu em tempo de execução, por tentar chamar um método através de um apontador nulo. Por sinal, foi um Segmentation Fault. Se o código acima fosse traduzido para Java, ocorreria a mesma coisa, só que com um NullPointerException, não?

Sim, mas perceba que a semântica do erro é diferente. Segmentation Fault é um acesso ilegal à memória, pode acontecer em várias ocasiões, por exemplo acessar uma posição de um array que não foi alocada. Já um NPE significa que você tentou enviar uma mensagem a um objeto que não existe.

V

Esse problema é impossível em java:

Class x* = new X(); delete x; cout &lt;&lt; x.toString();

Em c++, isso é um seg. fault.
Em java, não existe delete, portanto, isso é impossível.

Além disso, vale lembrar que em java o nullpointer exception vem acompanhado da stack trace do erro, o que torna o problema facilmente rastreável.

Em C++, é impossível fazer isso:

E, portanto, um método declarado como

Não vai aceitar null como parâmetro. Esse é, por sinal, um dos motivos pelo qual referências são mais seguras que ponteiros.

E

O artigo do Phillip já é muito bom, mas quem quiser ir um pouco mais fundo, é só dar uma lida do capítulo 10 do Page-Jones

S

leandrocm86:

Existe alguma regra geral de programação defensiva? Em cada método que criarmos devemos checar nossos parâmetros?
Ou jamais devemos setar variáveis com null? O que vocês acham dessa situação?

Temos várias formas de programação defensiva. Programação defensiva, por definição, é passiva (não ha ifs).
Existe práticas que evitam o problema do null, mas não o contornam. Isso é simples programação, não programação defensiva.

O exemplo do set que passa null : às vezes null é um valor válido e o set tem que testar pro null e fazer diferente quando é null.
Mas isso está relacionado ao contrato do objeto e não a programação defensiva. Repare que a exeção é IllegalArgumentException ?
Porque "Illegal’ ? Porque embora sendo um valor possivel, null, não é aceitável segundo as regras do método. Violação de Regras => Ilegal.

Programação defensiva acontece quando vc escreve codigo que funciona mesmo quando a referencia é nula. Por exemplo:

"a".equals(b);

é programação defensiva ( funciona com null e sem ifs). Repare que é diferente de

b.equals("a");

que para funcionar seria

if( b!=null) {b.equals("a")};

Quando vc usa o if vc não está de defendendo, vc está atuando para comprovar e decidir o que fazer depois.

G

segue tópico…

http://www.guj.com.br/posts/list/104378.java#563207

L

Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??
Estou fazendo um sistema Web (só jsp+servlet) que é baseado no padrão Command, de forma que qualquer ação requisitada através da View vai passar por um único servlet que, por fim, vai delegar o trabalho para um comando.
No meu caso, ao invés de encher de verificações de entradas nulas dentro dos comandos, eu poderia simplesmente fazer

try { comando.execute(request, response) } catch(NullPointerException e) { // Gerar saida amigavel sem quebrar o sistema }
Como a chamada de comando é genérica (toda ação vai sempre passar por aí), não precisaria tratar o NPE em nenhum outro lugar mais, e posso deixar todas as implementações dos comandos mais limpas, sem ter que ficar fazento if (x == null)… toda hora.

De qualquer forma eu ia ter que estar preparado para tratar entradas inválidas, já que não se pode esperar nada do usuário (em vez de usar a view o cara poderia entrar com qualquer coisa na URL do seu browser, por exemplo).

Essa não seria uma maneira muito simples e limpa de resolver o problema? O que acham?

R

Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.

L

Rubem Azenha:
Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.

Eu entendo…
Mas e se sempre que lá no código eu detecte uma variável null que não deveria ser null eu tenha o mesmo comportamento?
Como disse, num sistema web você pode esperar qualquer lenha do usuário (será que tem como e vale a pena bloquear entradas diretas na URL dos browsers?). De qualquer jeito eu ia ter que encher o sistema de verificação nula, e sempre reagir da mesma forma, enviando uma mensagem amigável de erro e redirecionando para algum lugar, a tela de login por exemplo…

Se tiver que ser assim, acho muito melhor centralizar a reação ao problema lá no catch… não?

G

Rubem Azenha:
Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.

Desculpe mas ninguém varreu nada pra debaixo do tapete ele tratou o erro da forma correta, ou vc conhece outra maneira de tratar uma Excpetion sem try/cacth ???

E não venha me dizer q seu código não tem try/catch para as exceções lançadas pela API do java q vai ser dificil acreditar…

R

leandrocm86:

Eu entendo…
Mas e se sempre que lá no código eu detecte uma variável null que não deveria ser null eu tenha o mesmo comportamento?
Como disse, num sistema web você pode esperar qualquer lenha do usuário (será que tem como e vale a pena bloquear entradas diretas na URL dos browsers?). De qualquer jeito eu ia ter que encher o sistema de verificação nula, e sempre reagir da mesma forma, enviando uma mensagem amigável de erro e redirecionando para algum lugar, a tela de login por exemplo…

Se tiver que ser assim, acho muito melhor centralizar a reação ao problema lá no catch… não?

Giulliano:

Desculpe mas ninguém varreu nada pra debaixo do tapete ele tratou o erro da forma correta, ou vc conhece outra maneira de tratar uma Excpetion sem try/cacth ???

E não venha me dizer q seu código não tem try/catch para as exceções lançadas pela API do java q vai ser dificil acreditar…

Não é o caso de encher o sistema com if (obj != null). Se um objeto esta vindo nulo quando não deveria estar, tem mais é que estourar uma exception mesmo, pois é bug.

Novamente, NPE é erro de programação. Mesmo que a NPE ocorra por causa de uma entrada errada do usuário (afina, você tem que validar a entrada, certo?). Existem N erros de programação que podem ocorrer no seu sistema (ClassCastException, etc). Além disso, tem as exceptions que podem ser lançadas por algum erro do ambiente (banco fora do ar, problemas de rede, etc). Fazer um sistema tolerante a falhas não é só ficar colocando um monte de try…catch.

Excessões que representem erro de sistema e não de negócio normalmente não devem ser tratadas pela aplicação. Eu geralmente deixo elas estourarem no AS ou no servlet container. O AS o e servlet container se encarregarão de fazer o logging da excessão e redirecionar para uma página de erro se corretamente configurados.

L

Ok, Ok…

Minha próxima pergunta então acaba mudando um pouco o foco, talvez eu tenha que fazer lá na seção de desenvolvimento web:
Como validar entradas do usuário?
Vendo que o usuário se interage com o sistema via browser e pode fazê-lo diretamente via URL (dispensando a interface), como validar a entrada a cada requisição do usuário?

Me parece uma tarefa impossível, a menos que tenha algum jeito de eu bloquear entradas diretas na barra de endereço. Afinal, na minha interface tem como eu confiar.
Esse problema do NULL fica mais grave em sistema web porque toda requisição de ação pode estar acompanhada com uma lista distinta de parâmetros string. Cada ação, ao ser executada, teria que pegar os seus parâmetros e verificar se eles realmente vieram…

São casos excepcionais de erros mas, sendo possíveis, o sistema tem que estar preparado né…

L

Eu não sei como funciona com os Frameworks tipo JSF, struts etc…
Mas pelo menos num sistema JSP+Servlet como o meu, tudo é feito baseado em parâmetros String que são enviados através do objeto request.
De lá você pode esperar qualquer coisa…

R

Frameworks web em geral fornecem um esquema para você validar a request antes de chegar na action.

S

leandrocm86:
Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??

Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )

M

sergiotaborda:
leandrocm86:
Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??


Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )


-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

R

Marcio Duran:

-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

Marcio, se sua aplicação estiver rodando dentro dum AS ou Servlet Container, deixe a excessão estourarno container, ele vai tratar de efetuar o logging e redirecionar para uma página de erro customizada (se você fizer a configuração de forma correta).

L

sergiotaborda:
leandrocm86:
Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??

Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )


Mas nesse caso eu tenho que resolver sim, ué. Se eu pegá-la lá no servlet (que é a minha intenção), cabe ao servlet ir pra página adequada e exibir a mensagem de erro (de forma limpa).
Eu to vendo a coisa da seguinte forma:
Não tem como (sem usar os frameworks, como é meu caso), ficar validando entradas no servlet. Então eu tenho 2 opções: Ou encho cada código com um monte de verificação ou simplesmente trato lá em cima no servlet. O efeito final deve ser o mesmo: Ir para alguma página com uma mensagem de erro adequada.

R

Não tem jeito cara, tem que validar a entrada do usuário de alguma maneira.

Se você optar por não tratar a entrada do usuário e deixar rolar um monte de NPE (ou coisa pior) por causa disso, não precisa tratar no servlet, deixe que o container capture a excessão e ele redireciona para uma página de erro.

http://edocs.bea.com/wls/docs61/webapp/web_xml.html#1017571

Fica algo assim (no seu web.xml):

<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>paginaDeErro.jsp</location>
</error-page>

O container ainda fará o logging da exception.

Alias, acho que toda aplicação web deveria ter um tratamento assim, idependente de validar ou não a entrada do usuário.

L

Rubem, então acho que vou fazer isso mesmo. Deixar configurado pro tomcat.
Porque num dá pra ficar enchendo o código de verificação o tempo todo, e dá menos ainda pra implementar no braço a validação que os frameworks fazem…
Também não pode fazer aparecer uma tela toda obscura lá pro usuário quando ocorrer o erro né…

Então acho que rola isso mesmo: deixa os nullpointers (onde não deveriam ocorrer) por conta do tomcat e apresentar uma tela de erro adequada.

R

Leandro,

validar entradas seu programa tem que fazer, tipo onde deveria ser número você tem que verificar se a String representa um número, onde é data verificar se a String é uma data. Se não estiver válido, mostrar mensagens pro usuário corrigir, tipo: “Campo xyz deve ser número”, “Data inválida”, etc.

Mas erros inesperados de programação que não deveriam acontecer, como NullPointerException, você deixa dar Exception e configura seu servidor para mostrar uma tela mais geral do tipo: “Desculpe-nos o transtorno, ocorreu um erro inesperado. Por favor entrar em contato.”. Seu usuário não precisa ver aquelas telas feias cheias de mensagens do Java com stackTraces. Daí seria interessante ter arquivos de log com os stackTraces dos erros para que você possa ver e corrigir.

R

leandrocm86:
Rubem, então acho que vou fazer isso mesmo. Deixar configurado pro tomcat.
Também não pode fazer aparecer uma tela toda obscura lá pro usuário quando ocorrer o erro né…
Então acho que rola isso mesmo: deixa os nullpointers (onde não deveriam ocorrer) por conta do tomcat e apresentar uma tela de erro adequada.

Legal :slight_smile:

Algum motivo especial para não utilizar nenhum framework web? Ou integrar algum framework de validação ao seu projeto?

L

Renato, é exatamente o que farei.
Esse tipo de verificação que você falou (campos de um formulário, por exemplo) eu vou fazer sim.

O que eu tava com medo é que não é IMPOSSÍVEL alguns parâmetros chegarem com problemas. Se o cara ignorar a interface e acessar alguma funcionalidade via URL direta, por exemplo, Deus sabe o que poderia chegar ou não chegar para o servlet. Mas é um caso extramamente excepcional, como vários outros que podem ocorrer.

Mas só agora, com a ajuda de vocês, eu me atentei para essa coisa: Não é necessário fazer um sistema 100% à prova de qualquer falha. Os casos muito excepcionais eu posso deixar o tomcat tratar exibindo uma mensagem de erro adequada. Eu não sabia que dá pra fazer isso.

O importante, como você disse, é não jogar uma tela imunda na cara do usuário quando o erro ocorrer.

L

Rubem, esse é um projeto relativamente simples. É o primeiro sistema web que to fazendo, pra trabalho de faculdade. Eu poderia estar usando frameworks, mas minha maior intenção aqui era aprender mesmo como as coisas funcionam (começar do zero). Como nunca tinha feito um sistema web antes, achei que seria interessante começar fazendo algo mais puro, sem frameworks ainda, até porque eu poderia me enrolar se não fosse assim…

Como efeito disso, muitas coisas já me aconteceram durante o desenvolvimento que já me adiantaram o valor necessário que devemos dar aos frameworks :-p

R

leandrocm86:

Como efeito disso, muitas coisas já me aconteceram durante o desenvolvimento que já me adiantaram o valor necessário que devemos dar aos frameworks :-p

You’ve taken your first step into a larger world. :slight_smile:

P

Oi,

É importante notar que a própria página que você inkou condena o uso de assertions no contexto deste tópico:

O fato de ser possível desligar assertions em runtime torna a parte de checagem um pouco vaga, IMHO. Testes unitários podem ajudar mas o custo em ter uma chacagem que usa exceções em vez de asserções é muito baixo para ser considerado na maioria dos casos.

leandrocm86:
Será que é viajar demais se eu pensar que seria melhor que Java não permitisse passar valores nulos como parâmetros e, além disso, não permitisse que um método que deve retornar algum tipo qualquer retorne null?
Enfim, será que seria bom que referências a objetos fossem tratadas assim como os tipos primitivos nessas situações?
Verificar se uma referência qualquer pode não ter sido inicializada sempre pode ser feito em tempo de compilação.

Sobre NullPointerException em específico (o artigo linkado cobre mais que isso) não só isso faz sentido como é o tipo de coisa que e espera de uma linguagem tipada estaticamente. Infelizmente a tipagem estática em java é bem meia-boca e cabe ao progrmador fazer este tipo de verificação.

S

leandrocm86:
sergiotaborda:

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )

Mas nesse caso eu tenho que resolver sim, ué. Se eu pegá-la lá no servlet (que é a minha intenção), cabe ao servlet ir pra página adequada e exibir a mensagem de erro (de forma limpa).

Até aqui tudo bem.

Claro que tem. Vc cria um conjunto de classes para fazer a validação.


Então eu tenho 2 opções: Ou encho cada código com um monte de verificação ou simplesmente trato lá em cima no servlet. O efeito final deve ser o mesmo: Ir para alguma página com uma mensagem de erro adequada.

Mas tratar “lá em cima no servlet” vc não trata NullPointer. Vc trata Throwable. Ou seja, vc captura toda e qualquer exceção. Loga-a e envia o usuário para uma tela agaradável com uma umensagem educada. Nâo deixa explodir na cada do servlet container nunca.

Tratamento de exceções é como tratamento de bomba atomica : não pode explodir nunca!

S

Marcio Duran:
sergiotaborda:

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )

-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

Se eu entendi a pergunta, vc quer saber como monituorar se o programador está tratando exceções corretamente.
Se não foi isso que vc quiz perguntar, é a isso que vou responder … :lol: :lol:

Vc pode usar ferramentas como o CheckStyle ou o PMD se vc tiver paciencia e conhecimento para criar uma regra de validação. O que é dificil, não pela ferramenta mas pelo caracter não -localizado das exeções. O melhor mesmo e colocar um desenvolvedor com experiencia em tratamento de exceções a verificar o codigo.

Tratamento de exceções é um conjunto de boas práticas relacionadas ao onde ao como.
Por exemplo, fazer catch de exeções e logar consumindo a exeção é errado normalmente. Exceto quando estamos na ultima camada do sistema ( um servlet por exemplo) . Uma ferramenta indicará sempre o erro porque ela não tem noção do que é “a ultima camada”.

M

Rubem Azenha:
Marcio Duran:

-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

Marcio, se sua aplicação estiver rodando dentro dum AS ou Servlet Container, deixe a excessão estourarno container, ele vai tratar de efetuar o logging e redirecionar para uma página de erro customizada (se você fizer a configuração de forma correta).

Neste contexto isso pode vir de Exceções lançadas Programaticamente (Criado por um desenvolvedor de uma determinada API ou vindas provinientes da JVM ou JVMs proprietárias), acho que isso é bem mais complexo.

S

Marcio Duran:
Rubem Azenha:
Marcio Duran:

-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

Marcio, se sua aplicação estiver rodando dentro dum AS ou Servlet Container, deixe a excessão estourarno container, ele vai tratar de efetuar o logging e redirecionar para uma página de erro customizada (se você fizer a configuração de forma correta).

Neste contexto isso pode vir de Exceções lançadas Programaticamente (Criado por um desenvolvedor de uma determinada API ou vindas provinientes da JVM ou JVMs proprietárias), acho que isso é bem mais complexo.

Márcio, se você tem uma exception de negócio, lançada programticaticamente, é muito fácil tratar isso e mostrar uma resposta para o usuário. No caso de exceções que você (sua aplicação) não saiba como tratar, você cria uma tela ou página padrão para ser exibida.

Não é necessário tratar cada um dos possíveis erros que venham a ocorrer.

M

Sim, e algo neste contexto mesmo !!!

O yourkit java http://www.yourkit.com/ , não seria mais completo, já que o CheckStyle você verifica codigos duplicados !!!

ArrayIndexOutOfBounds, ClassCastException, NullPointerException são startadas pela JVM, entretando isso esta correlacionado tanto com algoritmos de software mau projetados, ou outra situação quando ferramentas não alinhadas para identificar essas threads de forma precisa ao monitoramento em um algum ponto do ambiente do desenvolvimento que pode estar vindo do sistema ou fora dele, não seria corrento simular o sistema a ponto de ter esse efeitos previsíveis !!!

S

Marcio Duran:

ArrayIndexOutOfBounds, ClassCastException, NullPointerException são startadas pela JVM, entretando isso esta correlacionado tanto com algoritmos de software mau projetados, ou outra situação quando ferramentas não alinhadas para identificar essas threads de forma precisa ao monitoramento em um algum ponto do ambiente do desenvolvimento que pode estar vindo do sistema ou fora dele, não seria corrento simular o sistema a ponto de ter esse efeitos previsíveis !!!

Essas exeções são tipicamente erros de programação. Não de desenvolvimento ou projeto.
A forma de simular e estressar o sistema para validar que elas não acontecem é fazer testes unitários. Não outra forma mais segura.

M

Bom, por curiosidade o que me fez pensar em simular tais eventos foi um tecnologia chamada simjava.

SimJava:
A simjava simulation is a collection of entities each running in its own thread. These entities are connected together by ports and can communicate with each other by sending and receiving event objects. A central system class controls all the threads, advances the simulation time, and delivers the events. The progress of the simulation is recorded through trace messages produced by the entities and saved in a file.

É claro que tem uma outra finalidade, é orientada pra telecomunicação, mas eu imaginei o uso disso para adaptar em FrameWorks de soluções a atender situação de missão critica.

http://www.dcs.ed.ac.uk/home/hase/simjava/index.html

http://www.icsa.inf.ed.ac.uk/research/groups/hase/simjava/guide/tutorial.html#1.1

Claro que temos, ferramentas como Junit, XUnit, Jmeter, entre outras pra test e especializadas, mas não um instrumento orientado a simular estado e comportado de todo um cenário em n-tier.

Posso estar viajando mas a palavra chave é simular ocorrencia de exception em qualquer situação de estado, que pode vir de um estado programático ou pela JVM, dentro do meu sistema ou fora dele(compartilhado). O principio de SOA e algo assim, me permite atender serviços em sistema até não conhecido sem intervenção ou queda de produtividade..

S

Eu entendo a sua preocupação, mas ela é , se certa forma, infundada.
Exception que esperamos e sabemos resolveu vão estar explicitamente tratadas no codigo. Todas as outras são exeções que não esperamos e/ou não sabemos resolver. Logo, quando uma exceção inesperada (que tinhamos tratado) acontece, o objetivo é alterar o código e tratá-la. Eu entendo que vc queira algum framework que estresse o sistema tentando lançar todas as exçãoes possiveis, mas isso é na prática uma tarefa de altas porque o próprio conceito de exceção significa que não ha uma regra deterministica para saber como, quando e porque, uma execção será lançada.

Pode ser importante em software de misssão critica sim ( como aqueles dos quais dependem vidas) e é interessante.
Contudo, não é com um profiler (yourkit) que vc vai fazer isso ou um sistema de rede (simjava). É com um framework especifico que instrumente o código e comece a lançar exceções de todos os tipos. Contudo, isso pode levar a um sistema completamente inchado de tratamento de exceções que vc não sabe tratar. Logo, é tão util como um catch trowable no objeto da camada mais exterior.

V

Acho que você não leu tudo. Não sei se você não acompanhou o tópico e viu que o autor perguntou dos métodos privados e do estresse de fazer verificações o tempo todo, ou se a palavra “assertions” ligou um alerta na sua cabeça (já que verificar com assertions em métodos públicos é realmente erradíssimo).

Mas estavamos falando de métodos privados, e o artigo é bem explicito que, nesse contexto, é possível sim usar asseções:

Aliás, você também pode reler a primeira frase da citação que você mesmo colou.

Mas eu ainda sou mais restritivo nesse assunto. Eu considero todos os acessos que não são private como públicos. Isso porque o Java é muito permissivo quando o assunto são pacotes. Por isso, asserções para validação de pré-condições, só em métodos privados mesmo.

Você faz testes unitários em métodos privados?
Já ouvi falar de programadores que fazem. E de fato, chegam a usar reflexão para invoca-los.

M

[size=18][color=blue]Exception management and error tracking in J2EE[/color][/size]
[color=red]Develop an exception framework for handling errors in the J2EE world[/color]

:arrow: “Logo, é tão util como um catch trowable no objeto da camada mais exterior.”

O que atende o contexto logo abaixo ???

http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-exception.html?page=1

P

ViniGodoy:

Acho que você não leu tudo.

Você tem razão. Eu acompanhei o tópico, o que eu não percebi foi que você falava explicitamente de métodos privados.

V

pcalcado:
ViniGodoy:

Acho que você não leu tudo.

Você tem razão. Eu acompanhei o tópico, o que eu não percebi foi que você falava explicitamente de métodos privados.

Eu imaginei. Num tópico sobre programação defensiva, também ligaria alertas na minha cabeça ao ler sobre assertions. =D

S

Marcio Duran:
sergiotaborda:

É com um framework especifico que instrumente o código e comece a lançar exceções de todos os tipos. Contudo, isso pode levar a um sistema completamente inchado de tratamento de exceções que vc não sabe tratar. Logo, é tão util como um catch trowable no objeto da camada mais exterior.

[size=18][color=blue]Exception management and error tracking in J2EE[/color][/size]
[color=red]Develop an exception framework for handling errors in the J2EE world[/color]

:arrow: “Logo, é tão util como um catch trowable no objeto da camada mais exterior.”

O que atende o contexto logo abaixo ???

http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-exception.html?page=1

Entenda que isso não é um framework para testar exceções nem para controlar exceções. É um framework para facilitar ao programador ter que lidar com exceções, de quebra incluindo boas práticas. O mesmo vc pode concluir lendo:

http://sergiotaborda.wordpress.com/java/trabalhando-com-excecoes-conceitos/
http://sergiotaborda.wordpress.com/java/excecoes-boas-praticas-mas-praticas/

e particularmente
http://sergiotaborda.wordpress.com/java/excecoes-classes-utilitarias/
Só não me alongei tanto como o texto do javaworld.

O ponto é que: é o programador que controla as exceções, já que essa é uma tarefa que inclui seguir regras e fazer trade-offs que uma máquina teria dificuldade já que é preciso entender o significado do codigo, não só o codigo em si.

M
  • Bommmmm!!! tem razão deveria estar mesmo viajando, com tantos FrameWorks que estão surgindo por ai, achei que poderia achar um outro que tivesse essa idéia surreal !!! :lol: :lol: :lol:

Vou dar uma lida no seus artigos !!! :thumbup:

Criado 25 de setembro de 2008
Ultima resposta 30 de set. de 2008
Respostas 54
Participantes 12