6

このメソッドのブロックreturn内の両方の値でリソースリークの警告に悩まされたとき、私はEclipseで正常に動作していました:try

@Override
public boolean isValid(File file) throws IOException
{
    BufferedReader reader = null;
    try
    {
        reader = new BufferedReader(new FileReader(file));
        String line;
        while((line = reader.readLine()) != null)
        {
            line = line.trim();
            if(line.isEmpty())
                continue;
            if(line.startsWith("#") == false)
                return false;
            if(line.startsWith("#MLProperties"))
                return true;
        }
    }
    finally
    {
        try{reader.close();}catch(Exception e){}
    }
    return false;
}

reader変数をtryスコープ外で宣言し、ブロック内にリソースを追加し、他のブロックを使用して例外を無視し、ifをブロック内tryで閉じているため、リソースリークがどのように発生するのかわかりません...finallytry...catchNullPointerExceptionreadernull

私が知っていることから、finallyブロックは構造を離れるときに常に実行されるtry...catchため、ブロック内で値を返すと、メソッドを終了する前にブロックtryが実行されfinallyます...

これは次のように簡単に証明できます。

public static String test()
{
    String x = "a";
    try
    {
        x = "b";
        System.out.println("try block");
        return x;
    }
    finally
    {
        System.out.println("finally block");
    }
}

public static void main(String[] args)
{
    System.out.println("calling test()");
    String ret = test();
    System.out.println("test() returned "+ret);
}

その結果:

calling test()
try block
finally block
test() returned b

このすべてを知っているのに、ブロックResource leak: 'reader' is not closed at this location内でEclipseを閉じているかどうかをEclipseが教えてくれるのはなぜですか?finally


答え

この回答に、彼が正しいことを追加しnew BufferedReaderます。例外がスローされた場合、のインスタンスはガベージコレクターによる破棄時に開かれます。FileReaderこれは、変数に割り当てられず、finallyブロックが閉じないためです。readernull

これが、この可能性のあるリークを修正した方法です。

@Override
public boolean isValid(File file) throws IOException
{
    FileReader fileReader = null;
    BufferedReader reader = null;
    try
    {
        fileReader = new FileReader(file);
        reader = new BufferedReader(fileReader);
        String line;
        while((line = reader.readLine()) != null)
        {
            line = line.trim();
            if(line.isEmpty())
                continue;
            if(line.startsWith("#") == false)
                return false;
            if(line.startsWith("#MLProperties"))
                return true;
        }
    }
    finally
    {
        try{reader.close();}catch(Exception e){}
        try{fileReader.close();}catch(Exception ee){}
    }
    return false;
}
4

4 に答える 4

4

技術的には、BufferedReader が閉じられないパスがありreader.close()ます。例外をキャッチして何もしないため、例外がスローされる場合。これはreader.close()、catch ブロックに再度追加することで確認できます。

    } finally
    {
        try {
            reader.close();
        } catch (Exception e) {
            reader.close();
        }
    }

または、finally の try/catch を削除します。

    } finally
    {
            reader.close();
    }

これにより、警告が消えます。

もちろん、それはあなたを助けません。reader.close() が失敗した場合、再度呼び出しても意味がありません。問題は、コンパイラがこれを処理できるほど賢くないということです。したがって、できる唯一の賢明なことは@SuppressWarnings("resource")、メソッドに a を追加することです。

編集Java 7 を使用している場合、できる/すべきことは、try-with-resources 機能を使用することです。これにより、警告が正しく表示され、コードが簡単になり、finallyブロックが節約されます。

public boolean isValid(File file) throws IOException
{
  try(BufferedReader reader = new BufferedReader(new FileReader(file)))
  {
    String line;
    while ((line = reader.readLine()) != null)
    {
      line = line.trim();
      if (line.isEmpty())
        continue;
      if (line.startsWith("#") == false)
        return false;
      if (line.startsWith("#MLProperties"))
        return true;
    }
  } 
  return false;
}
于 2013-03-06T16:49:39.467 に答える
3

BufferedReaderコンストラクターが例外をスローした場合(メモリ不足など)、FileReaderリークが発生しています。

于 2013-03-06T16:50:02.307 に答える
1
//If this line throws an exception, then neither the try block
    //nor the finally block will execute.
    //That is a good thing, since reader would be null.
    BufferedReader reader = new BufferedReader(new FileReader(aFileName));
    try {
      //Any exception in the try block will cause the finally block to execute
      String line = null;
      while ( (line = reader.readLine()) != null ) {
        //process the line...
      }
    }
    finally {
      //The reader object will never be null here.
      //This finally is only entered after the try block is 
      //entered. But, it's NOT POSSIBLE to enter the try block 
      //with a null reader object.
      reader.close();
    }
于 2013-03-06T16:49:54.023 に答える
1

例外をスローできるのでclose()(なぜああ、なぜ彼らはそのように設計したのですか...) 私は二重の試行を使用する傾向があります

try {
  BufferedReader reader = new BufferedReader(new FileReader(file));
  try {
    // do stuff with reader
  } finally {
    reader.close();
  }
} catch(IOException e) {
  // handle exceptions
}

このイディオムは finally ブロック内の try/catch を排除するので、Eclipse を満足させるには十分かもしれません。

new BufferedReader(...)それ自体をスローすることはできませんが、コンストラクターがまたはをスローした場合、IOException技術的にはこれでもリークする可能性があります。FileReaderBufferedReaderRuntimeExceptionError

于 2013-03-06T16:54:45.537 に答える