Se o estado do objeto é inválido, devo lançar uma exceção ou retornar nulo?

Olá Guj’s!

Tenho uma pequena dúvida. Tenho uma classe Aluno que calcula a idade do mesmo dependendo de sua data de nascimento. Como o nascimento não é um campo obrigatório, não sei se é mais elegante retornar nulo ou lançar uma exceção caso o atributo nascimento esteja nulo. Segue abaixo um exemplo do código:

public class Aluno {

        private Long id;
	private String nome;
	private Date nascimento;
	private Sexo sexo;

        // setters and getters

       public Integer getIdade() {
		Calendar hoje = new GregorianCalendar();
		Calendar nasc = new GregorianCalendar();
		nasc.setTime(nascimento);
		
		Integer idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);
		if (hoje.get(Calendar.MONTH) < nasc.get(Calendar.MONTH)) {
			idade = idade - 1;
		}
		
		return idade;
	}

}

IMHO acho essa situação delicada. Na view por exemplo, se lançar uma exceção ia aparecer um stack trace na cara do usuário, mas se retornar nulo, a minha camada de negócio teria que ficar checando se o valor retornado pelo método getIdade é igual a nulo.

O que vocês tem feito nessas situações?

Abraços
Thiago

Bom dia!

Primeiramente, quando uma exceção é lançada, não há a necessidade explícita de mostrar o que aparece para o usuário.

Não sei se te ajuda, mas vai um exemplo abaixo do que pode-se fazer:

[code]
public Integer getIdade() {
Integer idade = null;
try {
Calendar hoje = new GregorianCalendar();
Calendar nasc = new GregorianCalendar();
nasc.setTime(new Date());

		idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);
		if (hoje.get(Calendar.MONTH) < nasc.get(Calendar.MONTH)) {
			idade = idade - 1;
		}
	} catch (Exception e) {

	} finally {
		return idade;
	}
}[/code]

Se conseguir processar, devolve idade com o valor correto, senão lança null. Sobre a classe de negócios ter que ficar verificando toda hora o se é nulo, não tem muito o que se fazer, a não ser que você devolva outro tipo de dado(tipo String) e inicialize com um valor que não vá afetar outras partes do programa(no caso “”).

Deu para ajudar?
Até!

Olá !

Considere que se não há uma entrada válida para o sistema, isto deve ser tratado. Retornar null, neste caso pode não ocasionar maiores problemas além da classe de negócio ter que controlar isso. Mas de maneira geral, o ideal é tratar como exceção. Não que esta tenha que ser exibida ao usuário, mas deve ser tratada. Em muitas situações, um retorno nulo acarreta problemas na aplicação no fluxo do processo.

Abraço.

humm, não era bem essa a minha dúvida… vou tentar exemplificar melhor…

1º - Lançando uma exceção:

[code]public Integer getIdade() {
if (nascimento == null) {
throw new IlegalStateException();
}

	Calendar hoje = new GregorianCalendar();
	Calendar nasc = new GregorianCalendar();
	nasc.setTime(nascimento);
	
	Integer idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);
	if (hoje.get(Calendar.MONTH) < nasc.get(Calendar.MONTH)) {
		idade = idade - 1;
	}
	
	return idade;
}[/code]

1º - Retornando nulo

[code]public Integer getIdade() {
if (nascimento == null) {
return null;
}

	Calendar hoje = new GregorianCalendar();
	Calendar nasc = new GregorianCalendar();
	nasc.setTime(nascimento);
	
	Integer idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);
	if (hoje.get(Calendar.MONTH) < nasc.get(Calendar.MONTH)) {
		idade = idade - 1;
	}
	
	return idade;
}[/code]

Eu não sou muito fã de ‘silenciar’ a exceção utilizando o try catch. IMHO, deve definir um padrão onde, ou lanço a exceção ou retorno nulo se nascimento estiver nulo.

[quote=luis.soares]Olá !

Mas de maneira geral, o ideal é tratar como exceção. Não que esta tenha que ser exibida ao usuário, mas deve ser tratada. Em muitas situações, um retorno nulo acarreta problemas na aplicação no fluxo do processo.

Abraço.[/quote]

Blz, também concordo que retornar nulo acarreta em problemas.

O principal fator de eu me questionar se deveria retornar nulo é por causa da view que chama o método getIdade. Exemplo:

<td><p>${aluno.idade}</p></td>

Se eu retornar nulo, o trecho de código acima se mantém inalterado, mas se lançar uma exceção ficaria assim:

[code]<c:if teste="${aluno.nascimento != null}">

${aluno.idade}

[/code]

Essa complexidade adicionada a view vale a pena?

Simples:

Todo aluno deve sempre ter uma idade? isto é uma invariante?

  • Se sim, quando não existir lance uma exceção (IllegalStateException é a clássica)
  • Se não, retorne null

Mais sobre isso em:

http://fragmental.com.br/wiki/index.php?title=Contratos_Nulos

no meu caso, nascimento não é uma invariante. Thanks, acho que minha questão foi esclarecida. :wink: