Как IOUtils.closeQuietly скрывает предупреждение об утечке ресурсов?

Фон

Есть хорошая функция, которую я использую в IOUtils называется «closeQuietly», который закрывает поток независимо от того, что там находится.

Например:

InputStream input = null;
try
  {
  ...
  input = connection.getInputStream();
  ...
  } 
catch(Exception e)
  {
  }
finally
  {
  IOUtils.closeQuietly(input);
  }

Каким-то образом он также скрывает предупреждение в Eclipse, когда я вызываю его в блоке finally, «Утечка ресурсов:« вход »не закрыт в этом месте».

Это означает, что в приведенном выше коде такого предупреждения нет.

Проблема

Я не понимаю, как он скрывает предупреждение о себе во «внешнем мире».

Что я пробовал

Я попытался проверить это, скопировав код этой библиотеки (пример здесь), но появляется предупреждение, когда я использую его в новом классе . Это не имеет смысла...

вот пример кода, который я создал, чтобы показать, что предупреждение будет появляться в ваших собственных классах:

public class MyIOUtils {
    public static void closeQuietly(final InputStream input) {
        if (input == null)
            return;
        try {
            input.close();
        } catch (final IOException ioe) {
        }
    }

    public static void closeQuietly(final OutputStream output) {
        if (output == null)
            return;
        try {
            output.close();
        } catch (final IOException ioe) {
        }
    }
}

Применение:

public class Test {
    public void test() {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("dummyFile.txt");
            int t = 0;
            --t;
            if (t < 0)
                return; // here you will get a warning
        } catch (final FileNotFoundException e) {
        } finally {
            MyIOUtils.closeQuietly(inputStream);
        }
    }
}

Вот что я вижу, включая установленную версию Eclipse:

введите здесь описание изображения

Вопрос

Как это делается?


person android developer    schedule 16.01.2014    source источник
comment
Что вы делаете с «выводом», ваш код этого не показывает.   -  person Kayaman    schedule 16.01.2014
comment
Код является примером. вывод может быть любым именем переменной. теперь я обновил вопрос, чтобы они соответствовали друг другу, чтобы избежать путаницы.   -  person android developer    schedule 16.01.2014
comment
@aquaraga ваша теория неверна, так как я уже писал, что пытался скопировать код закрытия потока в другой класс и использовать его, но появляется предупреждение ... плюс, это очень плохо реализованное предупреждение, если оно работал так, как вы предложили...   -  person android developer    schedule 16.01.2014
comment
@androiddeveloper Я не должен был просто строить догадки. Удалю свой комментарий.   -  person aquaraga    schedule 16.01.2014
comment
Да, это так. это то, что я тоже использую. Я обновил вопрос, чтобы показать проблему, если кто-то еще этого не понимает.   -  person android developer    schedule 20.01.2014
comment
Сейчас я провел тщательную проверку всех возможных ошибок/предупреждений, которые доступны в Eclipse Kepler SR1, но по умолчанию отключены. Я обнаружил как утечку ресурсов (по умолчанию включено), так и потенциальную утечку ресурсов (по умолчанию отключено). Включение последнего необходимо для воспроизведения вашей проблемы.   -  person Marko Topolnik    schedule 20.01.2014
comment
Ok. так как же библиотека преодолевает это предупреждение? и почему вы продолжаете писать и здесь, и в своем посте? это сбивает с толку... :\   -  person android developer    schedule 20.01.2014


Ответы (2)


Так почему же это работает для IOUtils? Команда eclipse сделала что-то очень простое — они жестко запрограммировали методы! В предыдущих версиях eclipse предупреждение тоже было, но начиная с версии 4.3 M4 оно исчезло, так как его исправили:

Released for 4.3 M4 via commit 277792ba446c3713bcfdc898c37875d45fc06c18.

The fix covers the following well-known methods:
- com.google.common.io.Closeables.closeQuietly(Closeable)
- com.google.common.io.Closeables.close(Closeable,boolean)
- org.apache.commons.io.IOUtils.closeQuietly(Closeable)

Подробнее см. здесь, особенно комментарии в конце...

ОБНОВЛЕНИЕ: Что это значит для вас? Вы должны использовать один из описанных выше методов или жить с предупреждением. Проверка в основном не сложная и не проверяет следующий уровень.

Обновление II: они в основном жестко запрограммировали имена файлов. Может быть, проще понять исходный код. Представьте, что это код затмения, проверяющий предупреждение:

public boolean showResourceWarning(){

//do somestuff to detect whether a potential ressource warning is shown
...
    if(resourceLeakWarning){
      if(this.checkForExceptions()){
       return false;
      }
    }
 return resourceLeakWarning;
}

private boolean checkForExceptions(){
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)"){
     return true;
    }
    if(name.equals("com.google.common.io.Closeables.close(Closeable,boolean)")){
     return true;
    }
    if(name.equals("org.apache.commons.io.IOUtils.closeQuietly(Closeable)")){
     return true;
    }
    // code executed for your method:
    return false;
}

=> В результате у вас нет возможности удалить предупреждение, кроме как напрямую использовать close() (не в подметоде!) или использовать один из трех методов, перечисленных выше.

Обновление III: взгляните на следующий класс TypeConstants.java. Вы видите там запрограммированные имена? Если вы хотите, чтобы он работал с вашим кодом, вам нужно добавить туда имя класса и метода, а затем перекомпилировать eclipse. Затем посмотрите на класс MessageSend.java, начиная со строки 90.

person Lonzak    schedule 24.10.2014
comment
Не могли бы вы привести пример того, как это сделать? - person android developer; 24.10.2014
comment
Смотрите мой комментарий - в принципе вы не можете предоставить свою собственную реализацию, иначе вы дадите ей то же имя и пакет. - person Lonzak; 24.10.2014
comment
Я не понимаю. Код был взят из библиотеки, и он не встроен в Android, поэтому конфликтов имен пакетов не было. Что вы предлагаете здесь? пожалуйста, объясни. - person android developer; 25.10.2014
comment
Но как они это сделали? Я имею в виду, что код находится просто в файле jar, и компилятор не должен работать по-другому, не так ли? - person android developer; 27.10.2014
comment
Хорошо, может быть, я не понимаю ваш вопрос. Что значит, как они это сделали? Я написал, как они это сделали: они не смотрят на содержание — только на имя (метода). Если появляется имя, предупреждение исчезает. Если имени там нет - будет предупреждение. - person Lonzak; 27.10.2014
comment
О, вы имеете в виду, что он встроен в плагин Eclipse JDT? они просто добавили проверку пакетов этих библиотек? - person android developer; 27.10.2014
comment
Я ожидал увидеть что-то особенное внутри библиотеки, а на самом деле все это что-то в самом JDT... Разочарован. В любом случае, благодарю Вас. Вы получили мой V и +1. - person android developer; 27.10.2014

Я не могу воспроизвести эту проблему в своей установке Eclipse, поэтому не могу проверить свое объяснение. Однако это то, что мы находим в http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CC0QFjAA&url=http%3A%2F%2Fhelp.eclipse.org%2Fjuno%2Ftopic%2Forg.eclipse .jdt.doc.user%2Ftasks%2Ftask-avoiding_resource_leaks.htm&ei=r-TeUvumDsXxoASN8IG4CA&usg=AFQjCNHeI8Ojm5VDlFo_9s-V3IvR7qYokw&sig2=jp9_tF3VbR0u_w6OHY3KOw&bvm=bv.21956.8

Оболочки ресурсов и закрывающиеся элементы без ресурсов

JDK определяет несколько классов, которые реализуют Closeable, но не представляют непосредственно ресурс на уровне операционной системы.

java.io.StringReader — это пример объекта close, который не требует вызова close(), поскольку нет ресурсов операционной системы, требующих очистки. Анализ использует явный белый список для обнаружения классов из java.io, подпадающих под эту категорию. Для этих классов не выдаются предупреждения об утечке ресурсов.

Экземпляры таких классов, как java.io.BufferedInputStream, представляют собой оболочки вокруг другого ресурса (где оболочки могут применяться на нескольких уровнях). Также эти объекты не представляют напрямую ресурс операционной системы. Если обернутый ресурс закрыт, обертку не нужно закрывать. И наоборот, если оболочка закрыта, это будет включать закрытие обернутого ресурса. Анализ имеет второй белый список для обнаружения ресурсов-оболочек и распознает, будет ли базовый фактический ресурс закрыт прямо или косвенно через оболочку. Любого из них достаточно, чтобы отключить предупреждения об утечке ресурсов. Белый список содержит классы из java.io, java.util.zip, java.security, java.beans и java.sound.sampled.

Подсказка: обычно предпочтительнее/безопаснее всего закрывать самую внешнюю оболочку, а не обернутый ресурс.

Согласно документации IOUtils, все методы этого класса, читающие поток, буферизуются внутри. Это означает, что нет причин использовать BufferedInputStream или BufferedReader. В тестах было показано, что размер буфера по умолчанию 4 КБ эффективен.

person Peter    schedule 21.01.2014
comment
но остается вопрос: как они это сделали? - person android developer; 22.01.2014