目的
- Eclipse では AutoCloseable の変数を作って、クローズしないと「リソース・リーク」の警告が出ます
- でも、AutoCloseable を実装しているはずの
java.util.stream.Stream
はクローズしなくても警告は出ない - どんなときに出るのか、少しだけ確認してみました
実験
Test.java
public class Test {
public static void resourceLeaks() throws Exception {
Stream<String> a = Stream.of("test.txt"); // #1. OK
a.count();
Stream<String> b = new MyStream<>(); // #2. ▲警告あり
b.count();
Stream<String> c = getMyStream(); // #3. OK
c.count();
Reader d = new StringReader("test.txt"); // #4. OK
d.read();
Reader e = new FileReader("test.txt"); // #5. ▲警告あり
e.read();
Reader f = getReader(); // #6. OK
f.read();
Reader in1 = new FileReader("test.txt"); // #7. OK
Reader bis1 = new BufferedReader(in1); // #8. ▲警告あり
bis1.read();
Reader in2 = new StringReader("test.txt"); // #9. OK
Reader bis2 = new BufferedReader(in2); // #10. OK
bis2.read();
}
private static <E> MyStream<E> getMyStream() {
return new MyStream<>(); // #11. OK
}
private static Reader getReader() throws IOException {
return new FileReader("test.txt"); // #12. OK
}
private static class MyStream<E> implements Stream<E> {
// 省略
}
}
とりあえずのまとめ
Eclipse のリソース・リークのチェックは以下のようになっていると思われます。
- クローズしなくてもよいクラス・インタフェース・メソッド等を知っているみたい(#1, #4)
- java.util.stream.Stream
- java.io.StringReader
- 他にもあるはず
- それ以外の AutoCloseable はクローズしないとダメ(#2, #5)
- java.io.FileReader
- 独自に継承・実装したクラスも同様
- おそらく「クローズ不要な物」のホワイトリスト方式なんでしょうね
- メソッドの戻り値などで受け取ったものは良くわからんから黙っておく(#3, #6)
- 今のところ、メソッドの中まで追いかけて解析はしていないみたい
- ラップするクラスも知っていると思われる
- java.io.BufferedReader など
- ラップされたものがクローズ要なら、ラップした側が警告(#7, #8)
- ラップされたものがクローズ不要なら、ラップした側も警告なし(#9, #10)
- 当然、リソースをリターンする場合には警告は出ない(#11, #12)
Eclipse の設定をざっとみた感じだと、クローズ不要のリストを追加することはできなさそう。
(Preferences の Java / Compiler / "Errors/Warning" / "Potential programming problems" / "Resource leak:" で報告レベルを変えることはできますね)
また、「このクラスはクローズ不要」だというアノテーションをつけることもできなさそう(何かあるのかな?)。
もちろん、使う変数やメソッドのところで @SuppressWarnings("resource")
をつければ警告は抑止できますが。
もし AutoCloseable を実装したクローズ不要のクラスを提供する場合には(コンストラクタではなく)インスタンスを生成するメソッドを用意した方がよさそうですね(上記#3,#6)。たぶん。