No caso de código em que você precisa fazer uma limpeza de recursos antes de sair de uma função, há uma grande diferença de desempenho entre essas duas maneiras de fazê-lo.
Limpando o Recurso Antes de Cada Declaração de Retorno
void func() { login(); bool ret = dosomething(); if(ret == false) { logout(); return; } ret = dosomethingelse(); if(ret == false) { logout(); return; } dootherstuff(); logout(); }
Limpando o Recurso em um Bloco Finalmente
void func() { login(); try { bool ret = dosomething(); if(ret == false) return; ret = dosomethingelse(); if(ret == false) return; dootherstuff(); } finally { logout(); } }
Fiz alguns testes básicos em programas de amostra e não parece haver muita diferença. Eu prefiro muito a finally
maneira de fazer isso - mas estava pensando se isso causaria algum impacto no desempenho de um grande projeto.
java
performance
efficiency
user93353
fonte
fonte
if(!cond)
, é o Java que me fez fazer isso. Em C ++, é assim que escrevo códigos tanto para booleanos quanto para outros tipos - ieint x;
if(!x)
. Como o java me permite usar isso apenas parabooleans
, parei totalmente de usar oif(cond)
&if(!cond)
in java.(someIntValue != 0)
que comparar e não avaliar booleanos. Isso cheira a mim, e refatoro-o imediatamente quando o vejo na natureza.Respostas:
Conforme indicado em Quão lenta são as exceções de Java? pode-se ver que a lentidão de
try {} catch {}
está dentro da instatiação da própria exceção.Criar uma exceção buscará toda a pilha de chamadas do tempo de execução e é aí que está a despesa. Se você não estiver criando uma exceção, isso representa apenas um aumento muito pequeno de tempo.
No exemplo dado nesta pergunta, não há exceções, não seria de esperar que as lentilhas fossem criadas - elas não foram criadas. Em vez disso, o que está aqui é
try {} finally {}
lidar com a desalocação de recursos dentro do bloco final.Portanto, para responder à pergunta, não, não há uma despesa real de tempo de execução dentro de uma
try {} finally {}
estrutura que não usa exceções (não é algo inédito, como visto). O que é possivelmente caro é o tempo de manutenção, quando alguém lê o código e vê esse estilo de código não típico, e o codificador precisa entender que algo mais acontece nesse método após oreturn
retorno à chamada anterior.Como foi mencionado, a manutenção é um argumento para ambas as maneiras de fazer isso. Para constar, após consideração, minha preferência seria a abordagem finalmente.
Considere o tempo de manutenção de ensinar a alguém uma nova estrutura de linguagem. Ver
try {} finally {}
não é algo que se vê frequentemente no código Java e, portanto, pode ser confuso para as pessoas. Há um certo tempo de manutenção para aprender estruturas um pouco mais avançadas em Java do que o que as pessoas estão familiarizadas em ver.O
finally {}
bloco sempre corre. E é por isso que você deve usá-lo. Considere também o tempo de manutenção da depuração da abordagem não definitiva, quando alguém se esquece de incluir um logout no momento apropriado, ou o chama no momento inadequado, ou se esquece de retornar / sair depois de chamá-lo para que seja chamado duas vezes. Existem tantos erros possíveis com isso que o uso detry {} finally {}
torna impossível de ter.Ao pesar esses dois custos, é caro em tempo de manutenção não usar a
try {} finally {}
abordagem. Embora as pessoas possam ponderar quantos milissegundos fracionários ou instruções jvm adicionais otry {} finally {}
bloco é comparado à outra versão, também é necessário considerar as horas gastas na depuração da maneira menos ideal de lidar com a desalocação de recursos.Escreva primeiro o código de manutenção e, de preferência, de forma a impedir que erros sejam gravados posteriormente.
fonte
/programming/299068/how-slow-are-java-exceptions
A resposta aceita nesta pergunta mostra que o empacotamento de uma chamada de função em um bloco catch try custa menos de 5% em uma chamada de função bare. Lançar e capturar realmente a exceção fez com que o tempo de execução aumentasse para mais de 66x a chamada de função simples. Portanto, se você espera que o design da exceção seja lançado regularmente, eu tentaria evitá-lo (no código crítico de desempenho com perfil adequado); no entanto, se a situação excepcional for rara, não será um grande problema.
fonte
Em vez de otimizar - pense no que seu código está fazendo.
Adicionar o bloco final é uma implementação diferente - significa que você fará logout em todas as exceções.
Especificamente - se o login gerar uma exceção, o comportamento na sua segunda função será diferente do seu primeiro.
Se o login e o logout não fizerem parte do comportamento da função, sugiro que o método faça uma coisa e outra bem:
e deve estar em uma função que já está encapsulada em um contexto que gerencia o logon / logout, pois estes parecem fundamentalmente diferentes do que seu código principal está fazendo.
Sua postagem está marcada como Java, que eu não conheço muito bem, mas no .net eu usaria um bloco usando para isso:
ou seja:
E o contexto de login possui um método Dispose que fará logout e limpará os recursos.
Edit: Na verdade, eu não respondi a pergunta!
Não tenho evidências mensuráveis, mas não esperaria que isso fosse mais caro ou, certamente, não o suficiente para ser digno de otimização prematura.
Vou deixar o resto da minha resposta porque, embora não tenha respondido à pergunta, acho que é útil para o OP.
fonte
using
construção .net , assumindo que o recurso em questão implementa aAutoCloseable
interface.ret
variável, que é apenas atribuída duas vezes para ser verificada uma linha depois. Faça issoif (dosomething() == false) return;
.ret2 = doSomethingElse(ret1)
, mas isso não é relevante para a pergunta, por isso foi removido.if (dosomething() == false) ...
é um código incorreto. Use o mais intuitivoif (!dosomething()) ...
Suposição: você está desenvolvendo no código C #.
A resposta rápida é que não há impacto significativo no desempenho ao usar os blocos try / finally. Há um impacto no desempenho quando você lança e captura exceções.
A resposta mais longa é ver por si mesmo. Se você observar o código CIL subjacente gerado ( por exemplo, refletor de porta vermelha) , poderá ver as instruções CIL subjacentes geradas e o impacto dessa maneira.
fonte
Como outros já mencionado, o código Ttese terá resultados diferentes, se quer
dosomethingelse
oudootherstuff
lançar uma exceção.E sim, qualquer chamada de função pode gerar uma exceção, pelo menos a
StackOVerflowError
! Embora seja raramente possível manipulá-los corretamente (como qualquer função de limpeza chamada provavelmente terá o mesmo problema, em alguns casos (como implementar bloqueios, por exemplo), é crucial manipular isso corretamente ...fonte