Pergunta

Eu lidei com casos em que eu jogaria / relançar uma exceção sabendo que o código circundante seria capturar a exceção específica. Mas há alguma vez que você gostaria de lançar uma exceção, sabendo que não seria pego?

Ou pelo menos, não capturar uma exceção?

Exceções suspender imediatamente a aplicação a menos que seu segurado para a direita? Então eu acho que eu estou perguntando se você nunca iria querer deixar propositadamente seu die aplicação?

Foi útil?

Solução

Se seu aplicativo está indo principalmente para ser usado por outros clientes e não é independente, ele geralmente faz sentido lançar exceções se uma condição surge que você não sabe (ou não quer) alça, e não há maneira sensata para que você possa recuperar-se. Os clientes devem ser capazes de decidir como querem lidar com todas as exceções que você pode jogar.

Por outro lado, se seu aplicativo é o ponto final, lançando uma exceção se torna essencialmente um mecanismo de notificação para alertar as pessoas de que algo deu terrivelmente errado. Nesses casos, você precisa considerar algumas coisas:

  • Como importante é a continuidade de funcionamento do aplicativo? este erro é realmente irrecuperável? lançar uma exceção e que encerra o programa não é algo que você quer fazer no ônibus espacial.

  • ?
  • Você está usando exceções como um proxy para registro verdadeiro Há quase nunca uma razão para fazer isso; considerar um mecanismo de registro real em vez. Capturar a exceção e ter o trabalho logger o que aconteceu.

  • O que você está tentando transmitir por lançar a exceção mesmo? Pergunte-se que o valor em jogar uma nova exceção é, e considerar cuidadosamente se não há uma maneira melhor de fazer o que você quer.

  • Não captura uma exceção pode deixar recursos em mau estado. Se você não fizer isso graciosamente saída, as coisas geralmente não são limpos para você. Certifique-se de entender o que você está fazendo se você precisar fazer isso. - E se você não está indo para pegá-lo, pelo menos, considerar um bloco try-finally que você possa fazer alguns arrumação

Outras dicas

Há uma regra muito boa que me deparei com um tempo atrás:

lançar uma exceção quando um método não pode fazer o que seu nome diz que faz.

A idéia é que uma exceção indica que alguma coisa tem de errado embora. Quando você está implementando um método, não é sua responsabilidade estar ciente de se ele será usado corretamente ou não. Se o código usando o método de captura a exceção ou não, não é da sua responsabilidade, mas a responsabilidade da pessoa que utiliza o método.

Outra regra a seguir é:

não pegar uma exceção se você não sabe o que você quer fazer com ele.

Obviamente, você deve incluir o código de limpeza em um try ... finalmente bloquear, mas você nunca deve apenas pegar uma exceção apenas por uma questão de captura-lo. E você nunca deve engolir exceções silenciosamente. Enquanto há ocasiões em que você pode querer capturar todas as exceções (por exemplo, fazendo catch (Exception ex) em C #), estes são muito raros e, geralmente, têm uma razão técnica muito específica. Por exemplo, quando você estiver usando threads no .NET 2.0 ou posterior, se uma exceção escapa de seu segmento, ele fará com que todo o domínio de aplicação para descarregar. Nesses casos, no entanto, no mínimo você deve registrar os detalhes da exceção como um erro e fornecer uma explicação nos comentários.

Geralmente, e, certamente, nas iterações iniciais de sua aplicação, não capturar a exceção. Mais frequentemente, a recuperação de uma exceção exigirá uma regra de negócio de algum tipo, e, na maioria das vezes, essas regras de negócio não estão definidos para você. Se você "pega" a exceção em vez de deixar a aplicação morrer, então você provavelmente será inventar regras de negócio para seu cliente. Não é bom.

O padrão geral de pegar todos os exceção apenas por uma questão de pegar isso me causou mais dores de cabeça do que eu posso contar. Isso geralmente acontece que alguém coloca algum tipo de código de manipulação de exceção genérica em toda a aplicação, o que inevitavelmente acaba escondendo um bug ou criar algum comportamento que é indesejada. (Aliás, captura e, em seguida, não rethrowing é ainda pior.)

Então, eu sugiro que você pedir em vez disso: "Quando eu deveria pegar uma exceção"

Claro. Por exemplo, se você está tentando carregar alguns bytes em uma string em Java:

try {
  String myString = new String(byteArray, "UTF-8");
} catch (UnsupportedEncodingException e) {
  // Platform doesn't support UTF-8?  What is this, 1991?
  throw new RuntimeExceptione(e);
}

Neste caso, não há nenhuma degradação graciosa, a plataforma simplesmente não pode suportar a operação desejada. Você pode verificar essa condição na inicialização tudo que você quer, mas o construtor para Cordas ainda lança essa exceção, e você tem que lidar com isso. Ou isso, ou o uso Charset.forName ():)

Aqui está a coisa ... trata-se de "camadas", ou "encapsulamento", ou "baixo acoplamento". Em algum lugar em sua base de código, você está escrevendo um método para fazer alguma coisa. Dizer que é um método público. Portanto, não deve assumir muito ou nada sobre o chamador ... em vez disso, deve apenas fazer o trabalho que é suposto fazer, independentemente de quem está chamando e que contexto o chamador estiver em.

E se, por algum motivo, não pode completar o seu trabalho, então ele precisa dizer ao chamador "Desculpe, eu não poderia fazer isso, e por isso aqui". As exceções são um excelente mecanismo para deixá-lo dizer ao chamador que (não é o único mecanismo, mas o melhor mecanismo que eu já vi para a maioria dos casos).

Assim, quando você lançar a exceção, você não tem idéia se ele vai ser preso ou não ... porque você está expondo um método público e você não tem idéia de quem poderia escolher para chamá-lo e por quê.

A captura da exceção é o trabalho do "contexto". Por exemplo, digamos que você está escrevendo uma biblioteca com métodos públicos que podem lançar exceções. Então, digamos que você está usando essa biblioteca a partir de um aplicativo de formulários do Windows. O Forms aplicativo do Windows pode capturar exceções e mostrar uma caixa de mensagem para o usuário.

Mas, mais tarde, você pode usar a mesma biblioteca a partir de um serviço do Windows. O serviço seria mais provável para capturar a exceção, registrá-lo, retornará um erro para o chamador original, mas manter a correr para que ele possa processar mais pedidos.

Assim, a exceção é como um acordo contratual entre o chamador eo fornecedor. O provedor diz: "Ou eu vou fazer o trabalho ou dizer-lhe porque eu não posso. O que você faz de lá é o seu próprio negócio." E o chamador diz, "OK, se você não pode fazer o trabalho, apenas me diga o porquê, e eu vou decidir o que fazer nesse caso."

Mas há alguma vez que você gostaria de lançar uma exceção, sabendo que não seria pego?

Eu diria que, se você está jogando manualmente uma exceção, na maioria das vezes você não sabe se ele vai ser pego. Se você sabia que seria pego você poderia simplesmente lidar com isso sozinho, em vez de lançar a exceção, em primeiro lugar.

Para ser justo, eu acho que depende em parte o tipo de programação que você está fazendo, e às vezes os mesmos fins programador construindo a biblioteca eo código que consome disse biblioteca.

Será que você nunca não capturar uma exceção?

Se você não esperava / não foram uma exceção consciente poderia ser acionada. Mas deixando isso de lado e supondo que você está ciente de exceção, às vezes você sabe sobre ele em um nível, mas sei que o próximo nível para cima é o lugar mais adequado para lidar com isso.

Depende do tipo de aplicação. aplicações web pode continuar a funcionar mesmo depois de exceções já borbulhava para o contexto de execução.

É comum a prática de 'lance / rethrow' uma exceção se você capturar a exceção em um nível onde ele não pode ser tratada. Mas, você quase sempre adicionar contexto para o problema, pelo menos adicionar um pouco de logging no nível mais alto para dizer que ele foi capturado e relançada.

Por exemplo

A chama B chama C (lança exceção)

B capturas / relança

pega um.

Neste caso, você gostaria B para adicionar um pouco de registro para que você possa diferenciar entre geração B e jogando um erro, e geradora de C e jogando um erro. Isso permitir-lhe uma maior capacidade para depurar problemas e corrigir mais tarde.

Em geral, você quase nunca querem uma exceção para matar seu programa. A melhor prática é para pegar a exceção e sair normalmente. Isso permite que você salve todas as informações e libertação abertas atualmente recursos que estão sendo usados ??para que eles não fiquem danificados. Se você pretende sair, você pode criar seu próprio 'núcleo-dump' relatório de informação que inclui as coisas que você estava fazendo quando você pegou a exceção fatal.

Se você deixar a exceção matar seu processo você está eliminando sua chance de obter customizado informações de falha, e você também está ignorando a parte onde você fornecer ao usuário com uma mensagem de erro amigável e depois sair.

Então, eu recomendo sempre captando exceções, e nunca deixar voluntariamente los correr amok em seu programa.

Editar

Se você estiver escrevendo uma biblioteca, você tem que escolher com antecedência se sua função irá lançar uma exceção, ou ser seguro exceção. Nesses casos, às vezes você vai lançar uma exceção e não tenho idéia se o chamador vai pegá-lo. Mas, nesse caso, a captura não é sua responsabilidade, enquanto a api declara que a função poderia lançar exceções. (Eu estou procurando uma palavra que significa 'poderia lançar exceção' ... Alguém sabe o que é? Vai me incomodar durante todo o dia.)

Em primeiro lugar, há absolutamente são situações em que é melhor não pegar uma exceção.

Às vezes, uma exceção às vezes pode dizer-lhe que o seu programa está em um estado desconhecido. Há uma série de excepções em que isso é muito bonito intrinsecamente verdadeira, dado o tipo de exceção. A NullReferenceException essencialmente diz que "há um bug". E pela captura de tal exceção, você pode esconder o erro, o que parece bom no curto prazo, mas no longo prazo você seria mais feliz para corrigi-lo. O produto não pode falhar, mas certamente não terá o comportamento esperado.

Mas isso também é verdade para os tipos de exceção que inventamos para nós mesmos. Às vezes, o fato de exceção Uma foi jogado deve ser "impossível." - e ainda assim tem acontecido, por isso há um bug

Além disso, algo muito importante acontece quando você capturar uma exceção: os blocos finally para toda a pilha de chamadas dentro do bloco try (e qualquer coisa que chama) será executada. O que esses blocos finally fazer? Bem, nada. E se o programa está em um estado desconhecido, eu realmente quero dizer qualquer . Eles poderiam apagar dados do cliente valioso do disco. Eles poderiam lançar mais exceções. Eles poderiam corromper os dados na memória, tornando o bug impossível diagnosticar.

Assim, quando uma exceção indica um estado desconhecido, você não quer correr mais código, para que faça o que fizer, não capturar a exceção . Deixá-lo voar passado, e seu programa será encerrado sem causar danos, e Relatório de Erros do Windows será capaz de capturar o estado do programa como era quando o problema foi detectado originalmente. Se você capturar a exceção, você vai causar mais código para executar, o que atrapalha o estado do programa ainda mais.

Em segundo lugar, você deve lançar uma exceção sabendo que não vai ser pego? Eu acho que essa pergunta não entende a natureza de métodos reutilizáveis. A idéia de um método é que ele tem um "contrato" que se segue: aceita certos parâmetros e retorna um determinado valor, além de também ele lança algumas exceções sob certas condições. Esse é o contrato - cabe ao chamador o que fazer com ele. Para alguns chamadores, exceção Um pode indicar uma condição recuperável. Para outros chamadores, ele pode indicar um erro. E pelo que eu disse acima, deve ficar claro que, se uma exceção indica um erro, deve não ser pego .

E se você está se perguntando o que isso significa para o exceção do Microsoft Enterprise Library manuseio de blocos : sim, é muito quebrado. Eles dizem para você catch (Exception x) e, em seguida, decidir se a relançar com base em sua política; tarde demais - os blocos finally já executado por esse ponto. Não faça isso.

Você provavelmente não quer um lugar exceção não pega onde os usuários finais podem vê-lo, mas muitas vezes é aceitável para permitir que os clientes da sua API (outros programadores) decidir como lidar com exceções.

Por exemplo, suponha que você está projetando uma biblioteca de classes Java. Você expõe um método público que leva em uma String. Em seu aplicativo, um valor de entrada nulo causaria um erro. Em vez de lidar com o erro mesmo, seria aceitável para verificar se há um valor nulo, em seguida, lançar uma IllegalArgumentException.

Você deve, naturalmente, documento que seu método lança esta exceção nessa circunstância. Este comportamento se torna parte do contrato do seu método.

Depende do que você entende por 'ser pego'. Algo, em algum lugar, eventualmente, captura a exceção seja o sistema operacional subjacente ou outra coisa.

Temos um sistema de fluxo de trabalho que os planos executa trabalho composta por trabalhos individuais. Cada tarefa é executada uma unidade de código. Por alguma das excepções, não queremos lidar com eles no código, mas jogá-lo até a pilha de modo que o sistema de fluxo de trabalho externo pega (o que acontece completamente fora do processo do lançador).

Se você estiver escrevendo todo o aplicativo, em seguida, suas razões são o seu próprio. Eu posso pensar em algumas situações onde você pode querem lançar a exceção e deixar morrer a aplicação, a maioria deles não são muito boas razões embora.

A melhor razão é geralmente quando a depuração. Eu freqüentemente desativar exceções durante a depuração para me permitir conhecer melhor onde algo está falhando. Você também pode simplesmente ligar breaks exceção lançada no depurador se você estiver executando-o em uma máquina com o depurador.

Outra possível razão é quando continuando depois de uma exceção é lançada não faz sentido ou resultaria em possível corrupção de dados irrecuperável ou pior (pense Robots com feixes de laser, mas, em seguida, você deve ser maldita certeza seus applicaiton lida com essas situações da OMI , deixando de funcionar o programa é apenas a maneira preguiçosa).

Se você está escrevendo código API, ou código Framework que você não vai usar a si mesmo, então você não tem idéia se alguém vai pegar suas exceções.

Sim, é a minha oportunidade SOMENTE para golpear o desenvolvedor consumir o serviço / object para dizer-lhes "Ur dO1n errado !!!!".

Isso e se livrar de possibilidades que você não quer permitir ou são aparentemente "impossível". Aplicativos que capturar todas as exceções e continuar são apenas um jardim murado rodeado pelo caos.

Se eu precisar de um sistema moderadamente grande que é de alguma forma o processamento de dados no que eu acredito ser uma forma consistente.

E

Em algum lugar ao longo da linha, eu detectar que o estado do aplicativo tornou-se inconsistente.

E

O sistema não (ainda) sabe como corrigir a inconsistência e recuperar graciosamente

Então, sim, eu iria lançar uma exceção com o máximo de detalhes possível e fazer com que o aplicativo para morrer tão rapidamente quanto possível, para evitar fazer qualquer outro dano aos dados. Se ele pode ser recuperado, seria importante não agravar o problema, tentando debilmente para encobrir a bagunça.

Mais tarde, ao longo da linha, uma vez que a cadeia de eventos que levaram à inconsistência é melhor compreendida, I maior facilidade pode pegar essa exceção, a reparação do Estado, e continuar com o mínimo de interrupção.

Uma biblioteca, muitas vezes vai lançar exceções com base em verificações de programação defensiva, deve uma condição surgir que não deveria ter sido autorizado a surgir pelo código do aplicativo. código de aplicativos, muitas vezes, ser escrito de tal forma que a maioria dessas condições inválidos nunca vai surgir, e, portanto, as exceções nunca vai ser jogado, então não há nenhum ponto de captura-los.

Dependendo do idioma (eu sou mais pensar em termos de C ++ em vez de C #, e não que claro quais são as diferenças) o efeito de uma exceção não pega realmente está sendo jogado é provavelmente o mesmo que o que costumava ser feito no dias antes exceções foram inventadas. Uma política comum de programação defensiva em bibliotecas C, por exemplo, era para terminar o programa imediatamente com uma mensagem de erro.

A diferença é que, se o lance exceção faz passar a ser possível (espero que isto vai ser descoberto através de testes de unidade), muitas vezes é relativamente fácil de adicionar um manipulador de exceção que pode recuperar do problema de uma forma mais construtiva. Você não tem que reescrever a biblioteca, ou adicionar verificações complexas no código do aplicativo para garantir a condição não pode surgir antes do call-jogando exceção é feita.

Eu tenho alguns exceção bastante lança que nunca são pegos. Todos eles são para fins defensivos, e ao ser uncaught é ruim para uma exceção que faz acontecer, isso só acontece sempre durante o desenvolvimento e testes, em busca de erros que eu não considerou no código do aplicativo até o momento. E quando isso acontece, é incomum para a correção para ser estranho - sem necessidade de uma refatoração grande escala, não há necessidade do código de aplicações a serem massivamente complicada com cheques condição de erro, apenas uma cláusula catch com uma recuperação relativamente simples ou " Sinto muito, Dave, eu tenho medo que eu não posso fazer isso." sem deixar o aplicativo inteiro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top