Eu tenho um método que deve retornar um objeto se ele for encontrado.
Se não for encontrado, devo:
- retornar nulo
- lançar uma exceção
- de outros
Eu tenho um método que deve retornar um objeto se ele for encontrado.
Se não for encontrado, devo:
Respostas:
Se você está sempre esperando encontrar um valor, lance a exceção, se estiver faltando. A exceção significaria que havia um problema.
Se o valor estiver ausente ou presente e ambos forem válidos para a lógica do aplicativo, retorne um valor nulo.
Mais importante: o que você faz em outros lugares no código? A consistência é importante.
GetPersonById(25)
jogaria se essa pessoa fosse excluída, mas GetPeopleByHairColor("red")
retornaria um resultado vazio. Então, acho que os parâmetros dizem algo sobre as expectativas.
Lance uma exceção apenas se for realmente um erro. Se o comportamento esperado para o objeto não existir, retorne o valor nulo.
Caso contrário, é uma questão de preferência.
Como regra geral, se o método sempre retornar um objeto, vá com a exceção. Se você antecipar o nulo ocasional e quiser lidar com isso de uma certa maneira, vá com o nulo.
Faça o que fizer, desaconselho a terceira opção: retornar uma sequência que diz "WTF".
Se nulo nunca indicar um erro, basta retornar nulo.
Se nulo é sempre um erro, lance uma exceção.
Se null for algumas vezes uma exceção, codifique duas rotinas. Uma rotina lança uma exceção e a outra é uma rotina de teste booleana que retorna o objeto em um parâmetro de saída e a rotina retorna false se o objeto não foi encontrado.
É difícil usar mal a rotina Try. É muito fácil esquecer de verificar se há nulo.
Então, quando nulo é um erro, basta escrever
object o = FindObject();
Quando o nulo não é um erro, você pode codificar algo como
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
e findOrFail
de Laravel Eloquent
TryFindObject
método? As tuplas parecem um paradigma preguiçoso para programadores que não desejam reservar um tempo para definir um objeto que encapsule vários valores. Isso é essencialmente todas as tuplas estão no centro de qualquer maneira.
Eu só queria recapitular as opções mencionadas anteriormente, lançando algumas novas em:
Ou você pode combinar estas opções:
Forneça várias versões sobrecarregadas do seu getter, para que o chamador possa decidir qual caminho seguir. Na maioria dos casos, apenas o primeiro tem uma implementação do algoritmo de pesquisa e os outros apenas envolvem o primeiro:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Mesmo se você optar por fornecer apenas uma implementação, convém usar uma convenção de nomenclatura como essa para esclarecer seu contrato, e isso ajudará você a decidir adicionar outras implementações também.
Você não deve usá-lo em excesso, mas pode ser útil, especialmente ao escrever uma classe auxiliar que você usará em centenas de aplicativos diferentes, com muitas convenções diferentes de tratamento de erros.
Expected<T> findObject(String)
onde Expected<T>
tem as funções orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Isso abstrai a obtenção dos dados do tratamento de erros.
Use o padrão de objeto nulo ou lance uma exceção.
Person somePerson = personRepository.find("does-not-exist");
vamos supor que esse método retorne um objeto nulo para o ID does-not-exist
. Qual seria então o comportamento correto somePerson.getAge()
? No momento, ainda não estou convencido de que o padrão de objeto nulo seja a solução certa para pesquisas de entidade.
Vantagens de lançar uma exceção:
Para obter mais explicações com exemplos, consulte: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
depende se seu idioma e código promoverem: LBYL (olhe antes de pular) ou EAFP (mais fácil pedir perdão do que permissão)
O LBYL diz que você deve verificar os valores (portanto, retorne um nulo) O
EAFP diz apenas para tentar a operação e ver se ela falha (lança uma exceção)
embora eu concorde com o acima. exceções devem ser usadas para condições excepcionais / de erro, e retornar um nulo é melhor ao usar verificações.
EAFP vs. LBYL em Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( arquivo da web )
Apenas pergunte a si mesmo: "é um caso excepcional que o objeto não foi encontrado"? Se é esperado que isso aconteça no curso normal do seu programa, você provavelmente não deve gerar uma exceção (já que não é um comportamento excepcional).
Versão curta: use exceções para lidar com um comportamento excepcional, não para lidar com o fluxo normal de controle em seu programa.
Alan.
As exceções estão relacionadas ao Design por contrato.
A interface de um objeto é na verdade um contrato entre dois objetos, o chamador deve cumprir o contrato ou o receptor pode apenas falhar com uma exceção. Existem dois contratos possíveis
1) todas as entradas que o método é válido; nesse caso, você deve retornar nulo quando o objeto não for encontrado.
2) apenas alguma entrada é válida, ou seja, a que resulta em um objeto encontrado. Nesse caso, você DEVE oferecer um segundo método que permita ao chamador determinar se sua entrada estará correta. Por exemplo
is_present(key)
find(key) throws Exception
SE e SOMENTE SE você fornecer os dois métodos do 2º contrato, você poderá lançar uma exceção se nada for encontrado!
Depende do que significa que o objeto não foi encontrado.
Se for um estado normal, retorne nulo. Isso é apenas algo que pode acontecer de vez em quando, e os chamadores devem verificar isso.
Se for um erro, em seguida, lançar uma exceção, os chamadores devem decidir o que fazer com a condição de erro do objeto ausente.
Em última análise, ambos funcionariam, embora a maioria das pessoas considere geralmente uma boa prática usar apenas exceções quando algo, bem, excepcional aconteceu.
Aqui estão mais algumas sugestões.
Se retornar uma coleção, evite retornar nulo, retorne uma coleção vazia que facilite o processamento da enumeração sem uma verificação nula.
Várias APIs .NET usam o padrão de um parâmetro thrownOnError que permite ao chamador escolher se é realmente uma situação excepcional ou não, se o objeto não for encontrado. Type.GetType é um exemplo disso. Outro padrão comum com BCL é o padrão TryGet, em que um booleano é retornado e o valor é passado através de um parâmetro de saída.
Você também pode considerar o padrão Null Object em algumas circunstâncias, que podem ser um padrão ou uma versão sem comportamento. A chave é evitar verificações nulas em toda a base de código. Veja aqui para mais informações http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Em algumas funções, adiciono um parâmetro:
..., bool verify = true)
Verdadeiro significa jogar, falso significa retornar algum valor de retorno de erro. Dessa forma, quem usa essa função possui as duas opções. O padrão deve ser verdadeiro, para o benefício daqueles que esquecem o tratamento de erros.
Retorne um nulo em vez de lançar uma exceção e documente claramente a possibilidade de um valor de retorno nulo na documentação da API. Se o código de chamada não respeitar a API e verificar o caso nulo, provavelmente resultará em algum tipo de "exceção de ponteiro nulo" de qualquer maneira :)
Em C ++, posso pensar em três tipos diferentes de configuração de um método que encontra um objeto.
Opção A
Object *findObject(Key &key);
Retorne nulo quando um objeto não puder ser encontrado. Agradável e simples. Eu iria com este. As abordagens alternativas abaixo são para pessoas que não odeiam parâmetros exagerados.
Opção B
void findObject(Key &key, Object &found);
Passe uma referência à variável que estará recebendo o objeto. O método gerou uma exceção quando um objeto não pode ser encontrado. Essa convenção provavelmente é mais adequada se não for realmente esperado que um objeto não seja encontrado - portanto, você lança uma exceção para indicar que é um caso inesperado.
Opção C
bool findObject(Key &key, Object &found);
O método retorna false quando um objeto não pode ser encontrado. A vantagem dessa opção A é que você pode verificar o caso de erro em uma etapa clara:
if (!findObject(myKey, myObj)) { ...
referindo-me apenas ao caso em que nulo não é considerado um comportamento excepcional, eu definitivamente sou o método try, é claro, não há necessidade de "ler o livro" ou "olhar antes de pular", como foi dito aqui
então, basicamente:
bool TryFindObject(RequestParam request, out ResponseParam response)
e isso significa que o código do usuário também ficará claro
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Geralmente, ele deve retornar nulo. O código que chama o método deve decidir se deve lançar uma exceção ou tentar outra coisa.
Ou retorne uma opção
Uma opção é basicamente uma classe de contêiner que força o cliente a lidar com casos de booth. Scala tem esse conceito, procure sua API.
Então você tem métodos como T getOrElse (T valueIfNull) nesse objeto para retornar o objeto encontrado ou uma alternativa às especificações do cliente.
Infelizmente, o JDK é inconsistente. Se você tentar acessar uma chave inexistente no pacote de recursos, não encontrará uma exceção e, ao solicitar o valor do mapa, será nulo se ele não existir. Então, eu mudaria a resposta do vencedor da seguinte forma: se o valor encontrado puder ser nulo, geraria uma exceção quando não for encontrado; caso contrário, retorne nulo. Portanto, siga a regra com uma exceção, se você precisar saber por que o valor não é encontrado, sempre aumente a exceção ou ..
Desde que deva retornar uma referência ao objeto, retornar um NULL deve ser bom.
No entanto, se estiver retornando a coisa toda sangrenta (como em C ++, se você fizer: 'return blá;' em vez de 'return blá;' (ou 'blá' é um ponteiro), não será possível retornar um NULL, porque é não do tipo 'objeto'. Nesse caso, lançar uma exceção ou retornar um objeto em branco que não possui um sinalizador de sucesso definido é como eu abordaria o problema.
Não pense que alguém mencionou a sobrecarga no tratamento de exceções - gasta recursos adicionais para carregar e processar a exceção, a menos que seja um verdadeiro evento de interrupção ou interrupção do processo de aplicativos (daqui para frente causaria mais danos do que benefícios). valor que o ambiente de chamada poderia interpretar como entender.
Concordo com o que parece ser o consenso aqui (retornar nulo se "não encontrado" for um resultado possível normal ou lançar uma exceção se a semântica da situação exigir que o objeto seja sempre encontrado).
Há, no entanto, uma terceira possibilidade que pode fazer sentido, dependendo da sua situação particular. Seu método pode retornar um objeto padrão de algum tipo na condição "não encontrado", permitindo que o código de chamada tenha certeza de que sempre receberá um objeto válido sem a necessidade de verificação nula ou captura de exceção.
Exceções devem ser excepcionais . Retorne nulo se for válido retornar um nulo .
Se o método retornar uma coleção, retorne uma coleção vazia (como dito acima). Mas não use Collections.EMPTY_LIST ou algo semelhante! (no caso de Java)
Se o método recuperar um único objeto, você terá algumas opções.
Cuidado, se você decidir retornar um nulo. Se você não é o único programador do projeto, receberá NullPointerExceptions (em Java ou qualquer outra linguagem) em tempo de execução! Portanto, não retorne nulos que não são verificados no momento da compilação.
null
. Veja a resposta mais votada para obter mais.
Se você estiver usando uma biblioteca ou outra classe que lança uma exceção, você deve repeti- la novamente . Aqui está um exemplo. Example2.java é como biblioteca e Example.java usa seu objeto. Main.java é um exemplo para lidar com essa exceção. Você deve mostrar uma mensagem significativa e (se necessário) empilhar o rastreamento para o usuário no lado de chamada.
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Example.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Isso realmente depende se você espera encontrar o objeto ou não. Se você seguir a escola de pensamento de que exceções devem ser usadas para indicar algo, bem, erre, excepcional ocorreu:
Caso contrário, retorne nulo.