Para evitar todas as respostas padrão que eu poderia ter pesquisado no Google, darei um exemplo que todos vocês podem atacar à vontade.
C # e Java (e muitos outros) têm, com muitos tipos, alguns dos comportamentos de 'estouro' que eu não gosto (por type.MaxValue + type.SmallestValue == type.MinValue
exemplo int.MaxValue + 1 == int.MinValue
:).
Mas, vendo minha natureza cruel, adicionarei algum insulto a essa lesão expandindo esse comportamento para, digamos, um DateTime
tipo Substituído . (Sei que DateTime
está selado no .NET, mas pelo exemplo deste exemplo, estou usando uma pseudo linguagem que é exatamente como C #, exceto pelo fato de que o DateTime não está selado).
O Add
método substituído :
/// <summary>
/// Increments this date with a timespan, but loops when
/// the maximum value for datetime is exceeded.
/// </summary>
/// <param name="ts">The timespan to (try to) add</param>
/// <returns>The Date, incremented with the given timespan.
/// If DateTime.MaxValue is exceeded, the sum wil 'overflow' and
/// continue from DateTime.MinValue.
/// </returns>
public DateTime override Add(TimeSpan ts)
{
try
{
return base.Add(ts);
}
catch (ArgumentOutOfRangeException nb)
{
// calculate how much the MaxValue is exceeded
// regular program flow
TimeSpan saldo = ts - (base.MaxValue - this);
return DateTime.MinValue.Add(saldo)
}
catch(Exception anyOther)
{
// 'real' exception handling.
}
}
É claro que um if poderia resolver isso da maneira mais fácil, mas o fato é que eu simplesmente não consigo entender por que você não pode usar exceções (logicamente, ou seja, eu posso ver que quando o desempenho é um problema, em certos casos as exceções devem ser evitadas). )
Eu acho que em muitos casos eles são mais claros que as estruturas if e não quebram nenhum contrato que o método está fazendo.
IMHO, a reação "Nunca os use para o fluxo regular do programa" que todo mundo parece ter não está tão bem construída quanto a força dessa reação pode justificar.
Ou estou enganado?
Eu li outras postagens, lidando com todos os tipos de casos especiais, mas o que quero dizer é que não há nada errado com isso, se vocês dois são:
- Claro
- Honre o contrato do seu método
Atire em mim.
fonte
if
declaração muito mais curta e auto-documentada . Você achará isso muito difícil. Em outras palavras: sua própria premissa é falha e as conclusões que você tira dela são, portanto, erradas.Respostas:
Você já tentou depurar um programa que gera cinco exceções por segundo no curso normal da operação?
Eu tenho.
O programa era bastante complexo (era um servidor de cálculo distribuído) e uma pequena modificação em um lado do programa poderia facilmente quebrar algo em um lugar totalmente diferente.
Eu gostaria de ter iniciado o programa e aguardar a ocorrência de exceções, mas houve cerca de 200 exceções durante a inicialização no curso normal das operações
O que quero dizer : se você usa exceções para situações normais, como localiza situações incomuns (ou seja, todas as exceções )?
Obviamente, existem outros motivos fortes para não usar exceções demais, principalmente em termos de desempenho.
fonte
Exceções são basicamente
goto
declarações não locais , com todas as consequências deste último. O uso de exceções no controle de fluxo viola um princípio de menor espanto , dificulta a leitura dos programas (lembre-se de que os programas foram escritos primeiro para os programadores).Além disso, não é isso que os fornecedores de compiladores esperam. Eles esperam que exceções sejam lançadas raramente, e geralmente deixam o
throw
código ser ineficiente. Lançar exceções é uma das operações mais caras do .NET.No entanto, algumas linguagens (principalmente Python) usam exceções como construções de controle de fluxo. Por exemplo, os iteradores geram uma
StopIteration
exceção se não houver mais itens. Até construções de linguagem padrão (comofor
) dependem disso.fonte
goto
, é claro, as exceções interagem corretamente com sua pilha de chamadas e com o escopo lexical e não deixam a pilha ou os escopos em uma bagunça.Minha regra de ouro é:
O problema que vejo com exceções é do ponto de vista puramente de sintaxe (tenho certeza de que a sobrecarga de desempenho é mínima). Não gosto de blocos de tentativa por todo o lado.
Veja este exemplo:
.. Outro exemplo pode ser quando você precisa atribuir algo a um identificador usando uma fábrica, e essa fábrica pode lançar uma exceção:
Então, pessoalmente, acho que você deve manter exceções para condições de erro raras (falta de memória etc.) e usar valores de retorno (classes de valor, estruturas ou enumerações) para fazer sua verificação de erro.
Espero ter entendido sua pergunta correta :)
fonte
Uma primeira reação a muitas respostas:
Claro! Mas um se simplesmente não é mais claro o tempo todo.
Não deveria ser surpreendente, por exemplo: dividir (1 / x) catch (divisionByZero) é mais claro do que qualquer outro para mim (no Conrad e outros). O fato de esse tipo de programação não ser esperado é puramente convencional e, de fato, ainda é relevante. Talvez no meu exemplo um if seria mais claro.
Mas DivisionByZero e FileNotFound são mais claros do que ifs.
É claro que se tiver menos desempenho e precisar de um zilhão de vezes por segundo, é claro que você deve evitá-lo, mas ainda não li nenhuma boa razão para evitar o design geral.
No que diz respeito ao princípio de menor espanto: existe o perigo de raciocínio circular aqui: suponha que uma comunidade inteira use um design ruim, esse design será esperado! Portanto, o princípio não pode ser um graal e deve ser considerado com cuidado.
Em muitas reações sth. assim brilha através. Apenas pegue eles, não? Seu método deve ser claro, bem documentado e com clareza de contrato. Não entendi essa pergunta, devo admitir.
Depurando em todas as exceções: o mesmo, isso é feito algumas vezes porque o design para não usar exceções é comum. Minha pergunta era: por que isso é comum em primeiro lugar?
fonte
x
antes de ligar1/x
? 2) Você envolve todas as operações de divisão em um bloco try-catch para pegarDivideByZeroException
? 3) Qual lógica você coloca no bloco catch para recuperarDivideByZeroException
?openConfigFile();
pode ser seguido por uma{ createDefaultConfigFile(); setFirstAppRun(); }
exceção FileNotFound capturada com FileNotFound manipulada normalmente; sem falhas, vamos melhorar a experiência do usuário final, não pior. Você pode dizer "Mas e se essa não fosse realmente a primeira corrida e eles conseguissem isso toda vez?" Pelo menos o aplicativo é executado todas as vezes e não está travando em todas as startups! Em um número de 1 a 10, "isso é terrível": "primeira execução" a cada inicialização = 3 ou 4, trava a cada inicialização = 10. #x
antes de ligar1/x
, porque geralmente é bom. O caso excepcional é o caso em que não está bem. Não estamos falando aqui de abalar a terra, mas, por exemplo, para um número inteiro básico dado aleatoriamentex
, apenas 1 em 4294967296 falharia em fazer a divisão. Isso é excepcional e as exceções são uma boa maneira de lidar com isso. No entanto, você pode usar exceções para implementar o equivalente a umaswitch
instrução, mas seria bem bobo.Antes das exceções, em C, havia
setjmp
elongjmp
que poderia ser usado para realizar um desenrolamento semelhante do quadro da pilha.Em seguida, a mesma construção recebeu um nome: "Exceção". E a maioria das respostas se baseia no significado desse nome para argumentar sobre seu uso, alegando que as exceções devem ser usadas em condições excepcionais. Essa nunca foi a intenção no original
longjmp
. Havia apenas situações em que você precisava interromper o fluxo de controle em muitos quadros de pilha.As exceções são um pouco mais gerais, pois você também pode usá-las no mesmo quadro de pilha. Isso levanta analogias com as
goto
quais acredito estarem erradas. Gotos são um par fortemente acoplado (e o sãosetjmp
elongjmp
). As exceções seguem uma publicação / assinatura pouco acoplada que é muito mais limpa! Portanto, usá-los no mesmo quadro de pilha dificilmente é a mesma coisa que usargoto
s.A terceira fonte de confusão refere-se ao fato de serem exceções marcadas ou desmarcadas. Obviamente, exceções não verificadas parecem particularmente terríveis para usar no fluxo de controle e talvez em muitas outras coisas.
No entanto, as exceções verificadas são ótimas para controlar o fluxo, uma vez que você supera todas as dificuldades vitorianas e vive um pouco.
Meu uso favorito é uma sequência de
throw new Success()
um longo fragmento de código que tenta uma coisa após a outra até encontrar o que está procurando. Cada coisa - cada parte da lógica - pode ter um aninhamento arbitrário, assimbreak
como também qualquer tipo de teste de condição. Oif-else
padrão é quebradiço. Se eu editarelse
ou alterar a sintaxe de alguma outra maneira, haverá um bug peludo.Usar
throw new Success()
lineariza o fluxo de código. UsoSuccess
classes definidas localmente - verificadas, é claro - para que, se eu esquecer de pegá-lo, o código não seja compilado. E eu não entendoSuccess
es de outro método .Às vezes, meu código verifica uma coisa após a outra e só é bem-sucedida se tudo estiver correto. Neste caso, eu tenho uma linearização semelhante usando
throw new Failure()
.O uso de uma função separada interfere com o nível natural de compartimentação. Portanto, a
return
solução não é ótima. Prefiro ter uma ou duas páginas de código em um único local por razões cognitivas. Não acredito em códigos divididos de maneira ultra fina.O que as JVMs ou os compiladores fazem é menos relevante para mim, a menos que haja um ponto de acesso. Não acredito que exista qualquer razão fundamental para os compiladores não detectarem exceções lançadas e capturadas localmente e simplesmente tratá-las como
goto
s muito eficientes no nível do código da máquina.Quanto a usá-los em funções para controle de fluxo - ou seja, para casos comuns e não para casos excepcionais - não vejo como eles seriam menos eficientes do que múltiplas interrupções, testes de condição e retornos para percorrer três quadros de pilha, em vez de apenas restaurar o ponteiro da pilha.
Pessoalmente, não uso o padrão entre os quadros de pilha e posso ver como isso exigiria sofisticação do design para fazê-lo com elegância. Mas, com moderação, deve ficar bem.
Por fim, em relação a programadores virgens surpreendentes, não é uma razão convincente. Se você gentilmente apresentá-los à prática, eles aprenderão a amá-la. Lembro que o C ++ costumava surpreender e assustar os programadores em C.
fonte
return
alternativa -pattern exigiria duas funções para cada uma dessas funções. Um externo para preparar a resposta do servlet ou outras ações desse tipo e um interno para fazer o cálculo. PS: Professor Um Inglês provavelmente sugere que eu uso "surpreendente" ao invés de "surpreendente" no último parágrafo :-)A resposta padrão é que as exceções não são regulares e devem ser usadas em casos excepcionais.
Uma razão, que é importante para mim, é que, quando leio uma
try-catch
estrutura de controle em um software que mantenho ou depuro, tento descobrir por que o codificador original usou um tratamento de exceção em vez de umaif-else
estrutura. E espero encontrar uma boa resposta.Lembre-se de que você escreve código não apenas para o computador, mas também para outros codificadores. Existe uma semântica associada a um manipulador de exceções que você não pode jogar fora apenas porque a máquina não se importa.
fonte
E quanto ao desempenho? Durante o teste de carga de um aplicativo da Web .NET, alcançamos 100 usuários simulados por servidor da Web até corrigirmos uma exceção comum e esse número aumentou para 500 usuários.
fonte
Josh Bloch lida com esse tópico extensivamente em Java eficaz. Suas sugestões são esclarecedoras e devem se aplicar ao .Net também (exceto pelos detalhes).
Em particular, as exceções devem ser usadas em circunstâncias excepcionais. As razões para isso estão relacionadas à usabilidade, principalmente. Para que um método seja usável ao máximo, suas condições de entrada e saída devem ser restringidas ao máximo.
Por exemplo, o segundo método é mais fácil de usar que o primeiro:
Em qualquer um dos casos, você precisa verificar se o chamador está usando sua API adequadamente. Mas no segundo caso, você precisa (implicitamente). As exceções suaves ainda serão lançadas se o usuário não leu o javadoc, mas:
O ponto principal é que as exceções não devem ser usadas como códigos de retorno, principalmente porque você complicou não apenas a SUA API, mas também a API do chamador.
Fazer a coisa certa tem um custo, é claro. O custo é que todos precisam entender que precisam ler e seguir a documentação. Espero que seja o caso de qualquer maneira.
fonte
Eu acho que você pode usar exceções para controle de fluxo. Existe, no entanto, um outro lado dessa técnica. Criar exceções é caro, porque eles precisam criar um rastreamento de pilha. Portanto, se você deseja usar Exceções com mais frequência do que apenas para sinalizar uma situação excepcional, é necessário garantir que a construção dos rastreamentos de pilha não influencie negativamente seu desempenho.
A melhor maneira de reduzir o custo de criação de exceções é substituir o método fillInStackTrace () como este:
Essa exceção não terá nenhum rastreamento de pilha preenchido.
fonte
Realmente não vejo como você está controlando o fluxo do programa no código que você citou. Você nunca verá outra exceção além da exceção ArgumentOutOfRange. (Portanto, sua segunda cláusula catch nunca será atingida). Tudo o que você está fazendo é usar um arremesso extremamente caro para imitar uma declaração if.
Além disso, você não está executando as operações mais sinistras em que apenas lança uma exceção para que ela seja capturada em outro lugar para executar o controle de fluxo. Você está realmente lidando com um caso excepcional.
fonte
Aqui estão as práticas recomendadas que descrevi na minha postagem no blog :
fonte
Como o código é difícil de ler, você pode ter problemas para depurá-lo, introduzirá novos bugs ao corrigi-los depois de um longo período de tempo, é mais caro em termos de recursos e tempo e o incomoda se você estiver depurando seu código e o depurador pára na ocorrência de todas as exceções;)
fonte
Além dos motivos expostos, um dos motivos para não usar exceções no controle de fluxo é que ele pode complicar bastante o processo de depuração.
Por exemplo, quando estou tentando rastrear um bug no VS, normalmente ativarei "interromper todas as exceções". Se você estiver usando exceções para controle de fluxo, estarei quebrando o depurador regularmente e terei que continuar ignorando essas exceções não excepcionais até que eu chegue ao problema real. É provável que isso enlouqueça alguém!
fonte
Vamos supor que você tenha um método que faça alguns cálculos. Existem muitos parâmetros de entrada que ele precisa validar e, em seguida, retornar um número maior que 0.
Usando valores de retorno para sinalizar erro de validação, é simples: se o método retornou um número menor que 0, ocorreu um erro. Como saber então qual parâmetro não foi validado?
Lembro-me dos meus dias C muitas funções retornaram códigos de erro como este:
etc.
É realmente menos legível do que lançar e capturar uma exceção?
fonte
Você pode usar uma garra de martelo para girar um parafuso, assim como você pode usar exceções para controlar o fluxo. Isso não significa que é o uso pretendido do recurso. A
if
declaração expressa condições, cujo uso pretendido é controlar o fluxo.Se você estiver usando um recurso de forma não intencional e optar por não usar o recurso projetado para esse fim, haverá um custo associado. Nesse caso, a clareza e o desempenho não sofrem nenhum valor agregado real. O que o uso de exceções lhe dá sobre a
if
declaração amplamente aceita ?Disse de outra maneira: só porque você pode , não significa que deveria .
fonte
if
o uso normal ou o uso de execuções não se destina porque não se destina (argumento circular)?public class ExitHelper{ public static void cleanExit() { cleanup(); System.exit(1); } }
Em seguida, basta chamar isso em vez de lançar:ExitHelper.cleanExit();
Se o seu argumento fosse sólido, essa seria a abordagem preferida e não haveria exceções. Você está basicamente dizendo "A única razão para exceções é travar de uma maneira diferente".if
.Como outros já mencionaram numerosamente, o princípio de menor espanto proibirá o uso excessivo de exceções apenas para fins de controle de fluxo. Por outro lado, nenhuma regra é 100% correta e sempre há casos em que uma exceção é "a ferramenta certa" - a exemplo de
goto
si mesma, a propósito, que é fornecida na formabreak
econtinue
em linguagens como Java, que geralmente são a maneira perfeita de saltar de loops muito aninhados, que nem sempre são evitáveis.A seguinte postagem no blog explica um caso de uso bastante complexo, mas também bastante interessante, para um não local
ControlFlowException
:Ele explica como, dentro do jOOQ (uma biblioteca de abstração SQL para Java) , essas exceções são ocasionalmente usadas para interromper o processo de renderização SQL mais cedo, quando alguma condição "rara" é atendida.
Exemplos de tais condições são:
Muitos valores de ligação são encontrados. Alguns bancos de dados não oferecem suporte a números arbitrários de valores de ligação em suas instruções SQL (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). Nesses casos, o jOOQ interrompe a fase de renderização do SQL e renderiza novamente a instrução SQL com valores de ligação embutidos. Exemplo:
Se extraíssemos explicitamente os valores de ligação da consulta AST para contá-los todas as vezes, desperdiçamos valiosos ciclos de CPU para aquelas 99,9% das consultas que não sofrem com esse problema.
Alguma lógica está disponível apenas indiretamente por meio de uma API que queremos executar apenas "parcialmente". O
UpdatableRecord.store()
método gera uma instruçãoINSERT
ouUPDATE
, dependendoRecord
dos sinalizadores internos do. Do lado de fora, não sabemos em que tipo de lógica está contidastore()
(por exemplo, bloqueio otimista, manipulação de ouvinte de eventos etc.), portanto, não queremos repetir essa lógica quando armazenamos vários registros em uma instrução em lote, onde gostaríamos destore()
gerar apenas a instrução SQL e não executá-la. Exemplo:Se tivéssemos externalizado a
store()
lógica na API "reutilizável" que pode ser personalizada para opcionalmente não executar o SQL, estaríamos tentando criar uma API bastante difícil de manter e dificilmente reutilizável.Conclusão
Em essência, nosso uso desses recursos não locais
goto
s é exatamente como o que [Mason Wheeler] [5] disse em sua resposta:Ambos os usos
ControlFlowExceptions
foram bastante fáceis de implementar em comparação com suas alternativas, permitindo reutilizar uma ampla gama de lógicas sem refatorá-la dos internos relevantes.Mas a sensação de que isso é uma surpresa para os futuros mantenedores permanece. O código parece bastante delicado e, embora tenha sido a escolha certa nesse caso, sempre preferimos não usar exceções no fluxo de controle local , onde é fácil evitar o uso de ramificações comuns
if - else
.fonte
Normalmente, não há nada errado, por si só, em lidar com uma exceção em um nível baixo. Uma exceção É uma mensagem válida que fornece muitos detalhes sobre por que uma operação não pode ser executada. E se você pode lidar com isso, você deve.
Em geral, se você sabe que existe uma alta probabilidade de falha que você pode verificar ... você deve fazer a verificação ... ou seja, se (obj! = Null) obj.method ()
No seu caso, não estou familiarizado o suficiente com a biblioteca C # para saber se a data e hora tem uma maneira fácil de verificar se um carimbo de data / hora está fora dos limites. Se isso acontecer, basta chamar if (.isvalid (ts)), caso contrário, seu código está basicamente bom.
Então, basicamente, tudo se resume à maneira como cria um código mais limpo ... se a operação para proteger contra uma exceção esperada for mais complexa do que apenas manipular a exceção; do que você tem minha permissão para lidar com a exceção, em vez de criar guardas complexos em todos os lugares.
fonte
Se você estiver usando manipuladores de exceção para o fluxo de controle, estará sendo muito geral e preguiçoso. Como outra pessoa mencionou, você sabe que algo aconteceu se estiver manipulando o processamento no manipulador, mas o que exatamente? Essencialmente, você está usando a exceção para uma instrução else, se estiver usando-a para o fluxo de controle.
Se você não souber qual estado possível pode ocorrer, poderá usar um manipulador de exceções para estados inesperados, por exemplo, quando precisar usar uma biblioteca de terceiros ou capturar tudo na interface do usuário para mostrar um bom erro mensagem e registre a exceção.
No entanto, se você sabe o que pode dar errado e não coloca uma declaração if ou algo para verificar, está apenas sendo preguiçoso. É preguiçoso permitir que o manipulador de exceções seja o item-chave de tudo que você sabe que pode acontecer e ele voltará a assombrá-lo mais tarde, porque você estará tentando corrigir uma situação no manipulador de exceções com base em uma suposição possivelmente falsa.
Se você colocar a lógica no seu manipulador de exceções para determinar o que exatamente aconteceu, seria bastante estúpido por não colocar essa lógica dentro do bloco try.
Manipuladores de exceção são o último recurso, pois quando você fica sem ideias / maneiras de impedir que algo dê errado, ou as coisas estão além da sua capacidade de controlar. Como, o servidor está inoperante e atinge o tempo limite e você não pode impedir que essa exceção seja lançada.
Finalmente, fazer todas as verificações antecipadamente mostra o que você sabe ou espera que ocorra e a torna explícita. O código deve ser claro na intenção. O que você prefere ler?
fonte
Você pode estar interessado em dar uma olhada no sistema de condições do Common Lisp, que é uma espécie de generalização de exceções feitas corretamente. Como você pode desenrolar a pilha ou não de maneira controlada, também obtém "reinicializações", o que é extremamente útil.
Isso não tem muito a ver com as práticas recomendadas em outros idiomas, mas mostra o que pode ser feito com algum pensamento de design (aproximadamente) na direção em que você está pensando.
É claro que ainda existem considerações de desempenho se você está pulando para cima e para baixo na pilha como um ioiô, mas é uma idéia muito mais geral do que o tipo de abordagem "oh merda, vamos salvá-la" que a maioria dos sistemas de exceção captura / joga incorporar.
fonte
Acho que não há nada de errado em usar exceções para controle de fluxo. As exceções são um pouco semelhantes às continuações e nas linguagens estaticamente tipadas; as exceções são mais poderosas que as continuações; portanto, se você precisar de continuações, mas seu idioma não as tiver, poderá usar as exceções para implementá-las.
Bem, na verdade, se você precisar de continuações e seu idioma não as possuir, você escolheu o idioma errado e deve usar um idioma diferente. Mas às vezes você não tem escolha: a programação da Web do lado do cliente é o principal exemplo - não há como evitar o JavaScript.
Um exemplo: Microsoft Volta é um projeto que permite gravar aplicativos da Web no .NET direto e permitir que a estrutura decida quais bits precisam ser executados para onde. Uma consequência disso é que Volta precisa poder compilar CIL para JavaScript, para que você possa executar o código no cliente. No entanto, há um problema: o .NET possui multithreading, o JavaScript não. Portanto, Volta implementa continuações em JavaScript usando Exceções de JavaScript e implementa Threads .NET usando essas continuações. Dessa forma, os aplicativos Volta que usam threads podem ser compilados para serem executados em um navegador não modificado - não é necessário o Silverlight.
fonte
Uma razão estética:
Uma tentativa sempre vem com uma pegadinha, enquanto uma if não precisa vir com outra.
Com try / catch, torna-se muito mais detalhado.
São 6 linhas de código a mais.
fonte
Mas você nem sempre saberá o que acontece nos métodos que você chama. Você não saberá exatamente onde a exceção foi lançada. Sem examinar o objeto de exceção em mais detalhes ....
fonte
Eu sinto que não há nada errado com o seu exemplo. Pelo contrário, seria um pecado ignorar a exceção lançada pela função chamada.
Na JVM, lançar uma exceção não é tão caro, apenas criando a exceção com o novo xyzException (...), porque o último envolve uma caminhada de pilha. Portanto, se você tiver algumas exceções criadas com antecedência, poderá lançá-las várias vezes sem custos. Obviamente, dessa forma, você não pode passar dados junto com a exceção, mas acho que é uma coisa ruim a se fazer.
fonte
Existem alguns mecanismos gerais através dos quais um idioma pode permitir que um método saia sem retornar um valor e desenrolar no próximo bloco "catch":
Faça com que o método examine o quadro da pilha para determinar o site de chamada e use os metadados do site de chamada para encontrar informações sobre um
try
bloco no método de chamada ou o local em que o método de chamada armazenou o endereço do chamador; na última situação, examine os metadados para determinar o chamador do chamador da mesma maneira que o chamador imediato, repetindo até encontrar umtry
bloco ou a pilha estar vazia. Essa abordagem adiciona muito pouca sobrecarga ao caso de nenhuma exceção (impede algumas otimizações), mas é cara quando ocorre uma exceção.Faça com que o método retorne um sinalizador "oculto", que distingue um retorno normal de uma exceção, e faça com que o chamador verifique esse sinalizador e ramifique para uma rotina de "exceção", se estiver definido. Essa rotina adiciona 1-2 instruções ao caso de exceção, mas relativamente pouca sobrecarga quando ocorre uma exceção.
Faça com que o chamador coloque as informações ou o código de tratamento de exceções em um endereço fixo relativo ao endereço de retorno empilhado. Por exemplo, com o ARM, em vez de usar a instrução "sub-rotina BL", pode-se usar a sequência:
Para sair normalmente, a sub-rotina faria simplesmente
bx lr
oupop {pc}
; no caso de uma saída anormal, a sub-rotina subtrairia 4 da LR antes de executar o retorno ou o usosub lr,#4,pc
(dependendo da variação do BRAÇO, modo de execução etc.) Essa abordagem funcionará muito mal se o chamador não for projetado para acomodá-la.Uma linguagem ou estrutura que utiliza exceções verificadas pode se beneficiar com a manipulação de mecanismos como os nºs 2 ou 3 acima, enquanto exceções não verificadas são tratadas com o nº 1. Embora a implementação de exceções verificadas em Java seja bastante incômoda, elas não seriam um conceito ruim se houvesse um meio pelo qual um site de chamada pudesse dizer, essencialmente: "Este método é declarado como jogando XX, mas não espero que fazer isso, se houver, repetir novamente como uma exceção "não verificada" .Em uma estrutura em que as exceções verificadas foram tratadas dessa maneira, elas poderiam ser um meio eficaz de controle de fluxo para coisas como métodos de análise que, em alguns contextos, podem ter um alta probabilidade de falha, mas onde a falha deve retornar informações fundamentalmente diferentes de sucesso. no entanto, não conheço nenhuma estrutura que use esse padrão. Em vez disso, o padrão mais comum é usar a primeira abordagem acima (custo mínimo para o caso sem exceção, mas alto custo quando são lançadas exceções) para todas as exceções.
fonte