Lançar uma exceção ou retornar null

Se eu tenho a function abaixo, com duas opções

private MyObject findBlank() { for (int i = 0; i < pieces.length; i++) { if(pieces[i].isBlank()){ return pieces[i]; } } return null; } private MyObject findBlank() { for (int i = 0; i < pieces.length; i++) { if(pieces[i].isBlank()){ return pieces[i]; } } throw new NoSuchFieldError("No blank piece found!"); } 

A partir desse método eu sei que ele deve sempre retornar um object que um dos ‘pedaços’ sempre é isBlank() == true , o retorno null no final é apenas para agradar o compilador. Desde que este é o caso e meu código não funcionaria de qualquer maneira se retornou null, este é o correto por favor lançar uma exceção?

Minhas opções são:

  1. return null e o aplicativo receberá um NullPointerException em algum caso de borda
  2. Retorna null e quebra o uso do método com checagens (myObject! = null)
  3. lançar uma exceção que irá explodi-lo em tempo de execução

Eu acho que o que eu estou perguntando é, este é o lugar correto para lançar uma exceção? ou seja, não há nada que eu possa fazer sobre isso se entrar na situação. Isso é classificado como “excepcional” ou devo verificar nulo o que meu método retorna (o que faz meu código parecer horrível). Se eu sei que não deveria retornar null, então eu deveria jogar a exceção certo?

Além disso, como eu escolheria qual exceção, ou estenderia uma e lançaria a minha?

Sobre suas opções, pergunte a si mesmo se

  1. É uma boa idéia ter seu programa explodido em algum momento depois que este método retornou um valor inesperado (isto é, null )?
  2. O que exatamente ficará oculto se você mascarar o valor de retorno null ?
  3. É uma boa idéia explodir imediatamente, só porque havia um valor errado?

Pessoalmente eu iria para a opção 2 ou 3, dependendo se eu gosto da resposta para a pergunta 2 ou 3 melhor. Opção 1 definitivamente é uma má ideia, especialmente se não for suposto acontecer. Se o programa lançar um caminho NPE após a devolução da sua function, você terá dificuldade em descobrir de onde veio o valor null . Especialmente se isso acontecer meses depois de você terminar de trabalhar nessa function específica.

Se você optar por lançar uma exceção, verá imediatamente onde algo deu errado e poderá ir diretamente para descobrir por que ela deu errado. Retornar null e verificar se está na function de chamada também pode funcionar, mas somente se você não falhar silenciosamente, mas realmente fizer algo para lidar com o problema corretamente.

Eu acho que o que eu estou perguntando é, este é o lugar correto para lançar uma exceção?

Se fosse uma situação excepcional , então sim. Se a possibilidade de não encontrar nada que corresponda aos critérios é esperada, então a situação não é excepcional e você deve retornar null .

Sim, você deve lançar uma RuntimeException para indicar uma situação “excepcional” que não deveria ter ocorrido. IllegalStateException provavelmente se encheckbox na conta. Certifique-se de include uma mensagem com qualquer informação que irá ajudá-lo a encontrar o bug, se alguma vez for lançado.

Retorno nulo a maior parte do tempo vai chamar a informação perdida do ponto de vista do contrato, o consumidor não pode saber qual é a razão para a resposta errada se obter o valor nulo do produtor.

Procurando seu primeiro código, há duas situações em que o código externo obtém o NULLPointerException: 1. As partes são nulas 2. As partes não possuíam tal elemento

Portanto, se retornar nulo, o código externo será guiado incorretamente para uma operação posterior, ele atrairá um problema em potencial.

E falar sobre diferença entre retornar nullObject (não nulo) e exceção, a principal diferença é PROBABILITY, que significa: 1. Se a situação vazia estiver em muito mais probabilidade, ela deve retornar nullObject para que TODOS os códigos externos possam / devam lidar com eles explicitamente . 2. Se a situação vazia é menos provável, por que não lançar a exceção para que a function de chamada final possa manipulá-la diretamente.

deve sempre retornar um object ou retornar null
e
o aplicativo receberá um NullPointerException em algum caso de borda
esses dois são contraditórios.

Se você está realmente certo de que você sempre tem pieces[i].isBlank() seguida, lançar IllegalStateException

Caso contrário, manuseie o gabinete de acordo com suas necessidades.

Se você array sempre deve ter um valor válido para retornar, você deve levantar uma exceção como um fallback. (Caso 2sd no seu exemplo)

Eventualmente, você pode declarar seu próprio tipo (Class) de exceção.

Eu sugeriria usar o tipo de dados Maybe (também conhecido como Option ) sobre o qual acabei de falar em outra resposta há um tempo atrás.

Este tipo de dados está disponível no Java funcional .

Uso:

 private Option findBlank() { for (int i = 0; i < pieces.length; i++) { if(pieces[i].isBlank()){ return Option.some(pieces[i]); } } return Option.none(); } 

Nota:

Seu método findBack pode ser generalizado para um método que usa um predicado como argumento e localiza e retorna o primeiro elemento que o satisfaz.

Sem surpresa, o Functional Java já tem isso também .

Vamos supor por um momento que as pieces sejam uma fj.data.List . Então seu método pode ser reescrito como:

 private Option findBlank() { return pieces.find(new F1() { public Boolean f(MyObject p) { return p.isBlank(); } }); } 

Outro sidenote:

Talvez o código acima pareça bastante complicado. O "fechamento dobrável" do IntelliJ IDEA pode ser de alguma ajuda aqui .

Pode ser uma boa ideia usar o padrão Objeto Nulo .

Provide an object as a surrogate for the lack of an object of a given type. The Null Object provides intelligent do nothing behavior, hiding the details from its collaborators

Então, nesse caso, você não terá que usar exceções ou retornar null. Você sempre pode retornar o object de tipo de retorno desejado. O truque é quando você não tem nada para retornar, em vez de retornar null ou lançar uma exceção, você pode retornar o Null object que é do mesmo tipo que o tipo de retorno desejado.

Esta documentação tem alguns exemplos e descrições. E tem um caso semelhante ao seu, resolvido pelo padrão de design.

 public class CustomerFactory { public static final String[] names = {"Rob", "Joe", "Julie"}; public static AbstractCustomer getCustomer(String name){ for (int i = 0; i < names.length; i++) { if (names[i].equalsIgnoreCase(name)){ return new RealCustomer(name); } } return new NullCustomer(); } } 

Além da maioria das respostas, gostaria de salientar que, se o desempenho é sua preocupação, as Exceções são muito mais lentas do que retornar null

Dê uma olhada neste código:

 class Main { public static void main(String[] args) { testException(); testNull(); } public static void testException() { long st = System.currentTimeMillis(); for(int i=0;i<10000000;i++) { try{ exp(); } catch(Exception e) { } } long et = System.currentTimeMillis(); System.out.println("Time taken with exceptions : "+(et-st)); } public static void testNull() { long st = System.currentTimeMillis(); for(int i=0;i<10000000;i++) { returnNull(); } long et = System.currentTimeMillis(); System.out.println("Time taken with null : "+(et-st)); } public static void exp() throws Exception { throw new Exception(); } public static Object returnNull() { return null; } } 

Os resultados na minha máquina são:

 Time taken with exceptions : 7526 Time taken with exceptions : 5 

Se a exceção de lançamento for uma condição rara no seu código e não acontecer com frequência, o tempo gasto em ambas as situações será quase o mesmo.

Você terá que fazer o desempenho versus manutenabilidade / legibilidade compensar.

Leia mais sobre isso aqui

Intereting Posts