Alternativas para return null

Exacto. Da mesma forma que se um método me devolve um objecto eu espero que seja o que eu pedi.
Se não existe o que pedi, devolve null ou, se não fizer sentido não exisitir, devolve uma excepção.

[quote=pmlm]
Exacto. Da mesma forma que se um método me devolve um objecto eu espero que seja o que eu pedi.
Se não existe o que pedi, devolve null ou, se não fizer sentido não exisitir, devolve uma excepção.[/quote]

Então, mas quando ele te devolve null, não está devolvendo o que você pediu.
Estou esperando uma cerveja e vem algo diferente que não posso utilizar como cerveja.

Seria o mesmo de conferir com o garçom se o que veio é realmente cerveja.

Nesse contexto jogar a exceção que não tem mais cerveja seria mais coerente, na minha opinião.

Isso depende do contrato. Se colocarmos em um cartaz-javadoc no meio do salão: “O garçom retornará de mãos vazias quando a cerveja da marca solicitada não estiver disponível no estoque”, então o null passa a ter este significado.
Também poderia lançar uma BeerNotFoundException, como vc sugeriu.
Ou então trazer uma NullBeer que é a garrafa vazia…

A escolha da melhor maneira depende do contexto. Claro que na analogia da cerveja eu preferiria que ele retornasse uma mensagem, qualquer uma das outras opções seria um pouco ridícula rsrs.

Mas enfim…
O importante é não beber a noite inteira e na hora da conta tentar lançar uma MoneyNotFoundException, aí o bicho pega pro seu lado :smiley:

Voltando ao tema,
se um método pode retornar null, então antes de utilizar o seu resultado eu tenho de verificar se ele é null.
Porque hei-de implementar uma classe para resolver um problema que eu já resolvo com um if?

Pensando dessa forma, porque hei de utilizar polimorfismo se resolvo isso com um if?

Se trabalhamos com objetos, porque de repente parar de utiliza-los?

Não paramos de utiliza-los.
Se um objecto não existe, para mim, não faz sentido devolver um outro objecto. Mas isso sou eu… cada um é livre de pensar e fazer como acha melhor.

[quote=pmlm]Voltando ao tema,
se um método pode retornar null, então antes de utilizar o seu resultado eu tenho de verificar se ele é null.
Porque hei-de implementar uma classe para resolver um problema que eu já resolvo com um if?[/quote]
Esses IFs podem ser evitados desde que faça sentido para o negócio que está sendo modelado. Vou mostrar um exemplo:

Você tem um site onde os usuários podem entrar como Visitante ou com um login de usuário registrado.
O usuário registrado tem acesso a diversas funcionalidades dependendo de seu perfil, e o usuário visitante não tem acesso a nenhuma das funcionalidades restritas.
Quando o usuário se loga, um objeto do tipo User é armazenado na sessão, e contém as permissões deste usuário que podem ser verificadas através da chamada de um método.

User user = session.getAttribute("user");
if (user.permiteTransacaoXXX()) {
// .... Faz operação restrita
}

Uma primeira maneira de tratar os usuários visitantes seria colocar um null na sessão toda vez que alguém clica em “Entrar como visitante”. Aí para evitar o nullpointerexception, o trecho acima ficaria assim:

User user = session.getAttribute("user");
if (user != null && user.permiteTransacaoXXX()) {
// .... Faz operação restrita
}

Esse teste adicional se espalharia por todo o código… porém há um jeito mais elegante. Quando um usuário clica em “Entrar como visitante”, armazenamos na Sessão um usuário com todas as transações desabilitadas, de modo que as chamadas aos métodos permiteTransacaoXXX() sempre retornem false.
Assim fica garantido que sempre há uma instância de User na sessão, e podemos voltar ao código mais simples.

User user = session.getAttribute("user");
if (user.permiteTransacaoXXX()) {
// .... Faz operação restrita
}

E pronto! Esse usuário visitante é um NullObject. É uma solução que surge naturalmente, e que faz todo o sentido dentro do negócio.

Neste caso não tinhamos o caso de um utilizador não existente mas sim utilizador visitante. São coisas diferentes.

Você se refere a “Utilizador não existente” no sentido de um usuário que não existe no banco de dados? Se sim, esse é um outro caso, um erro no processo de login.

No meu exemplo, não estou falando de um “usuário não existente” porque o login é inválido, mas sim de um caso de usuário inexistente na sessão de utilização atual, ou em outras palavras, estou navegando sem um usuário.

Na situação a que você se refere, creio que uma Exception seria o melhor tratamento.
Em meu exemplo, temos um caso que seria resolvido com null ou um NullObject.

Pois é justamente isso, o UsuarioVisitante é o NullObject de Usuario! Trata-se de uma instância do objeto com comportamento “neutro” ou “nulo”. (Repare que está de acordo com a definição do pattern NullObject).

É um exemplo bem semelhante ao que está no livro do Joshua Block, em que ele sugere que a VM deveria fornecer um LaxSecurityManager quando a aplicação estiver sendo executada sem nenhum SecurityManager.


Ah, só reiterando uma coisa aqui: estou apenas dando um exemplo válido de utilização do NullObject, sei que é uma situação diferente da descrita pelo autor do tópico, no caso uma pesquisa que não retorna o registro esperado.

Essa discussão é interessante para aqueles que gostam de escovar bytes. Um colega aqui citou o tal do “NIL” que siginifica “NULL” em Ruby, e esse cara realmente é um objeto e não um ponteiro sem instância.

Em Python, todas as classes estendes PyObject, assim como em Java todas as classes estendem Object. Então eu posso ao invés de retornar nulo, retornar um objeto do tipo PyObject ou Object. Assim evitaríamos o nulo. Porém em Java isso não é possível, por que a linguagem é do tipo Compilada enquanto que Ruby e Phyton são linguagens Interpretadas. Você até pode retornar um “new Object()” em caso de nulo, mas aí seria preciso fazer um “cast” e antes do cast fazer um IF. Ou seja, voltaria a estaca zero.

Retornar uma instância do mesmo objeto, vazio, seria uma “boa” prática, mas nem todo objeto permite uma sua criação sem “estado e métodos”. O que temos no final é uma restrição da linguagem Java, que por hora nos força a encher o código com “xxx != null”.