throws Exception em blocos finally
Pergunta
Existe uma maneira elegante de lidar com exceções que são lançadas no bloco finally
?
Por exemplo:
try {
// Use the resource.
}
catch( Exception ex ) {
// Problem with the resource.
}
finally {
try{
resource.close();
}
catch( Exception ex ) {
// Could not close the resource?
}
}
Como evitar a try
/ catch
no bloco finally
?
Solução
Eu costumo fazê-lo como este:
try {
// Use the resource.
} catch( Exception ex ) {
// Problem with the resource.
} finally {
// Put away the resource.
closeQuietly( resource );
}
Em outra parte:
protected void closeQuietly( Resource resource ) {
try {
if (resource != null) {
resource.close();
}
} catch( Exception ex ) {
log( "Exception during Resource.close()", ex );
}
}
Outras dicas
Eu normalmente uso um dos métodos closeQuietly
em org.apache.commons.io.IOUtils
:
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
Se você estiver usando Java 7 e implementos resource
AutoClosable
, você pode fazer isso (usando InputStream como um exemplo):
try (InputStream resource = getInputStream()) {
// Use the resource.
}
catch( Exception ex ) {
// Problem with the resource.
}
Provavelmente um pouco mais do topo, mas talvez útil se você está deixando exceções bolha e você pode não log qualquer coisa de dentro de seu método (por exemplo, porque é uma biblioteca e você preferir deixar as chamadas exceções identificador de código e logging):
Resource resource = null;
boolean isSuccess = false;
try {
resource = Resource.create();
resource.use();
// Following line will only run if nothing above threw an exception.
isSuccess = true;
} finally {
if (resource != null) {
if (isSuccess) {
// let close throw the exception so it isn't swallowed.
resource.close();
} else {
try {
resource.close();
} catch (ResourceException ignore) {
// Just swallow this one because you don't want it
// to replace the one that came first (thrown above).
}
}
}
}
UPDATE: Eu olhei para isso um pouco mais e encontrou um grande post de alguém que tenha claramente pensado nisso mais do que eu: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of -stream.html Ele vai um passo além e combina as duas exceções em um, que eu podia ver ser útil em alguns casos.
A partir do Java 7, você não precisa mais recursos fechar explicitamente em um finalmente bloco em vez disso você pode usar tente sintaxe -com-recursos. A instrução try-with-recursos é uma instrução try que declara um ou mais recursos. Um recurso é um objeto que deve ser fechada após o programa é terminado com ele. Os garante instrução try-com-recursos que cada recurso é fechada no final da declaração. Qualquer objeto que implementa java.lang.AutoCloseable, que inclui todos os objetos que implementam java.io.Closeable, pode ser usado como um recurso.
Suponha o seguinte código:
try( Connection con = null;
Statement stmt = con.createStatement();
Result rs= stmt.executeQuery(QUERY);)
{
count = rs.getInt(1);
}
Se qualquer exceção acontece o Fechar método será chamado em cada um desses três recursos na ordem inversa em que foram criados. Isso significa que o método close seria chamado pela primeira vez para ResultSetm então a Declaração e no final para o objeto de conexão.
Também é importante saber que todas as exceções que ocorrem quando os métodos de perto é chamado automaticamente são suprimidos. Estas excepções suprimidos podem ser recuperados por
Fonte: https://docs.oracle.com/javase/ tutorial / essencial / exceções / tryResourceClose.html
Ignorando exceções que ocorrem em um bloco 'finalmente' é geralmente um má idéia , a menos que se saiba o que essas exceções serão e quais as condições que irão representar. No padrão de uso try/finally
normal, o bloco try
lugares coisas em um estado do código fora não vai estar esperando, e o bloco finally
restaura o estado dessas coisas para o que o espera de código fora. código fora que captura uma exceção geralmente esperar que, não obstante a excepção, tudo foi restaurado para um estado normal
. Por exemplo, suponha que algum código inicia uma transação e, em seguida, tenta adicionar dois registros; os "finalmente" executa bloco a "reversão se não for cometido" a operação. Um chamador pode ser preparado para uma exceção para ocorrer durante a execução da segunda "adicionar" operação, e pode esperar que, se ele pega essa excepção, o banco de dados estará no estado em que estava antes de qualquer operação foi tentada. Se, no entanto, ocorre uma segunda exceção durante a reversão, coisas ruins poderiam acontecer se o chamador faz quaisquer suposições sobre o estado de banco de dados. O fracasso reversão representa um principal crise -. Um que não deve ser pego de código esperando um mero "Falha ao adicionar registro" exceção
A minha inclinação pessoal seria ter um finally exceções método de captura que ocorrem e envolvê-los em uma "CleanupFailedException", reconhecendo que tal falha representa um grande problema e tal excepção não deve ser pego de ânimo leve.
Uma solução, se as duas exceções são duas classes diferentes
try {
...
}
catch(package1.Exception err)
{
...
}
catch(package2.Exception err)
{
...
}
finally
{
}
Mas às vezes você não pode evitar esta segunda try-catch. por exemplo. para fechar um fluxo
InputStream in=null;
try
{
in= new FileInputStream("File.txt");
(..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
}
catch(SQLException err)
{
//handle exception
}
finally
{
//at the end, we close the file
if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
}
Por que você quer evitar o bloco adicional? Desde o último bloco contém operações "normais", que pode lançar uma exceção E você quer o bloco finally para executar completamente você tem que capturar exceções.
Se você não espera que o bloco finally para lançar uma exceção e você não sabe como lidar com a exceção de qualquer maneira (você simplesmente despejar rastreamento de pilha) deixe a bolha exceção na pilha de chamada (remover o try-catch do bloco finally).
Se você quiser reduzir a digitação você poderia implementar um bloco try-catch "global" exterior, que vai pegar todas as exceções lançadas em blocos finally:
try {
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
} catch (Exception ex) {
...
}
Depois de muita consideração, eu acho o seguinte código melhor:
MyResource resource = null;
try {
resource = new MyResource();
resource.doSomethingFancy();
resource.close();
resource = null;
} finally {
closeQuietly(resource)
}
void closeQuietly(MyResource a) {
if (a!=null)
try {
a.close();
} catch (Exception e) {
//ignore
}
}
Isso garante código a seguir:
- O recurso é liberado quando o código terminou
- Exceções lançadas ao fechar o recurso não são consumidos sem processá-los.
- O código não tentar fechar o recurso duas vezes, nenhuma exceção desnecessária será criado.
Se você pode, você deve testar para evitar a condição de erro, para começar.
try{...}
catch(NullArgumentException nae){...}
finally
{
//or if resource had some useful function that tells you its open use that
if (resource != null)
{
resource.Close();
resource = null;//just to be explicit about it was closed
}
}
Além disso, você provavelmente só deve estar pegando exceções que você pode recuperar, se você não pode recuperar, em seguida, deixá-lo propagar para o nível superior do seu programa. Se você não puder teste para uma condição de erro que você terá que cercar o seu código com um bloco try catch como você já fez (embora eu recomendaria ainda específica captura, erros esperados).
Você poderia refatorar isso em outro método ...
public void RealDoSuff()
{
try
{ DoStuff(); }
catch
{ // resource.close failed or something really weird is going on
// like an OutOfMemoryException
}
}
private void DoStuff()
{
try
{}
catch
{
}
finally
{
if (resource != null)
{
resource.close();
}
}
}
Eu costumo fazer isso:
MyResource r = null;
try {
// use resource
} finally {
if( r != null ) try {
r.close();
} catch( ThatSpecificExceptionOnClose teoc ){}
}
Justificativa: Se eu sou feito com o recurso e o único problema que tenho é fechá-lo, não há muito que eu possa fazer sobre isso. Não faz sentido tanto para matar o tópico inteiro se eu sou feito com o recurso de qualquer maneira.
Este é um dos casos em que, pelo menos para mim, é seguro ignorar que exceção verificada.
Para este dia, eu não tive nenhum problema usando este idioma.
try {
final Resource resource = acquire();
try {
use(resource);
} finally {
resource.release();
}
} catch (ResourceException exx) {
... sensible code ...
}
feito Job. Nenhum teste nulos. Único captura, incluem aquisição e liberação de exceções. Claro que você pode usar a Cerca Executar idioma e só tem que escrever uma vez para cada tipo de recurso.
Alterar Resource
de melhor resposta para Closeable
Streams implementos Closeable
Assim, você pode reutilizar o método para todos os fluxos
protected void closeQuietly(Closeable resource) {
if (resource == null)
return;
try {
resource.close();
} catch (IOException e) {
//log the exception
}
}