Pergunta

Tudo bem, tenho vindo a fazer o seguinte (nomes de variáveis ??foram alterados):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

Recentemente, eu comecei a usar FindBugs, o que sugere que não estou fechando corretamente córregos. Eu decido para ver se há alguma coisa que pode ser feito com um bloco finally {}, e então eu vejo, oh sim, close () pode lançar IOException. O que as pessoas devem fazer aqui? As bibliotecas Java jogar muitas exceções verificadas.

Foi útil?

Solução

Para Java 7 e acima tentar-com-recursos deve ser utilizado:

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Se você está preso em Java 6 ou abaixo ...

Este padrão evita perder tempo com nulo :

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

Para uma mais detalhes sobre como lidar eficazmente com próximo , leia este post: Java: como não fazer uma confusão de fluxo de manipulação . Tem código mais de amostra, mais profundidade e cobre as armadilhas de embrulho próximo em captura bloco.

Outras dicas

Algo como o seguinte deve fazê-lo, até você se você joga ou engolir o IOException na tentativa de fechar o fluxo.

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}

Você pode usar o tentar- com-recursos recurso acrescentou JDK7. Ele foi criado precisamente para lidar com este tipo de coisas

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

O documenation diz:

Os garante instrução try-com-recursos que cada recurso é fechado no final da declaração.

Você também pode usar um estático simples método auxiliar:

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

e usar isso de seu bloco finally.

Nada muito a acrescentar, com exceção de uma sugestão estilística muito menor. O exemplo canônico de código de auto documentando se aplica neste caso -. Dar um nome de variável descritivo ao IOException ignorado que você deve pegar close()

Assim, a resposta de Squiddle torna-se:

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}

Na maioria dos casos, eu acho que é apenas melhor não para capturar as exceções IO, e simplesmente usar try-finally:

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

Com exceção de FileNotFoundException, você geralmente não pode "trabalhar em torno de" um IOException. A única coisa que resta a fazer é relatar um erro, e você normalmente irá lidar com isso mais acima na pilha de chamadas, assim que eu achar que é melhor para propagar a exceção.

Desde IOException é uma exceção verificada, você terá que declarar que este código (e qualquer um dos seus clientes) throws IOException. Isso pode ser muito barulhento, ou você pode não querer revelar o detalhe de implementação do uso de IO. Nesse caso, você pode envolver todo o bloco com um manipulador de exceção que envolve o IOException em um RuntimeException ou um tipo de exceção abstrato.

Detalhe: Estou ciente de que o código acima engole qualquer exceção do bloco try quando a operação close no bloco finally produz uma IOException. Eu não acho que é um grande problema: geralmente, a exceção do bloco try será o mesmo IOException que faz com que o close a falhar (ou seja, é muito raro que IO para funcionar bem e depois não no ponto de fechamento) . Se esta é uma preocupação, pode valer a pena o trabalho de "silêncio" do fim.

A solução a seguir joga corretamente uma exceção se perto falhar sem esconder uma possível exceção antes do encerramento.

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

Isso funciona porque chamando perto uma segunda vez não tem efeito .

Esta depende de goiaba Closeables , mas pode-se escrever o seu próprio método closeQuietly se preferido, como mostrado por Squiddle (ver também serg10 ).

Reportando um erro de perto, no caso geral, é importante porque perto pode escrever alguns bytes finais para o fluxo, por exemplo, por causa do buffering. Assim, o usuário quer saber se ele falhou, ou você provavelmente vai querer agir de alguma forma. Concedido, isso pode não ser verdade no caso específico de um FileInputStream, eu não sei (mas por razões já mencionadas Eu acho que é melhor para relatar um erro de perto, se ocorrer de qualquer maneira).

O código acima é um pouco difícil de entender devido à estrutura dos blocos try embutidos. Ele pode ser considerado mais clara com dois métodos, um que lança uma IOException e um que pega. Pelo menos é o que eu iria optar.

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

Com base http :. //illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html (referenciado por McDowell)

Esperamos obter fechamentos em Java algum dia, e depois vamos perder muito a verbosidade.

Assim, em vez haverá um somwhere método auxiliar no javaIO que você pode importar, ele provavelmente tem uma interface "Closable" e também um bloco. Dentro desse método auxiliar o try {closable.close ()} catch (IOException ex) {// blah} é definido uma vez por todas, e então você vai ser capaz de escrever

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }

Você está preocupado principalmente com a obtenção de um relatório limpa a partir de FindBugs ou com ter código que funciona? Estes não são necessariamente a mesma coisa. Seu código original é bom (embora eu iria se livrar do cheque if (fis != null) redundante uma vez que um OutOfMemoryException teria sido jogado de outra forma). FileInputStream tem um método finalizador que irá fechar o fluxo para você no caso improvável de que você realmente receber um IOException em seu processamento. É simplesmente não vale o incômodo de fazer o seu código mais sofisticado para evitar o cenário extremamente improvável de

  1. você receber um IOException e
  2. isso acontece tantas vezes que você começa a ter problemas finalizador backlog.

Editar: se você está recebendo tantas IOExceptions que você está correndo em problemas com a fila finalizador, então você tem muito, muito maior peixe para fritar! Este é sobre a obtenção de um senso de perspectiva.

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