Объект сканера имеет атрибут класса вместо инициализации кода - PullRequest
0 голосов
/ 29 мая 2020

Сегодня я столкнулся с проблемой с объектом Scanner при программировании серверного / клиентского приложения. Я решил проблему, но не понимаю, почему мое решение решило проблему.

Сначала в моем приложении было предупреждение об утечке памяти при компиляции проекта (JAVA 8, eclipse), потому что я использовал Scanner, чтобы запросить ввод от пользователя, но не закрыл его. Когда я пытаюсь закрыть сканер, мой другой класс выдает исключение, например java.util.NoSuchElementException. Я узнал, что у меня была аналогичная проблема: Невозможно использовать несколько объектов Scanner в Java, но между классами. Когда я закрывал сканер в классе, другой сканер класса (потока) не мог работать. (java .util.NoSuchElementException)

Решение, которое я нашел для решения этой проблемы, заключалось в том, чтобы поместить функцию сканера в качестве члена функции класса:

public class ClientThread extends Thread {

    private Scanner scanner;

   /*some code*/

}

При этом я потерял предупреждение об утечке памяти.

Почему использование сканера в качестве члена класса разрешило предупреждение? Это из-за деструктора класса?

Ответы [ 2 ]

0 голосов
/ 05 июня 2020

Хотя Java обычно автоматически освобождает память, когда вы покидаете область видимости, некоторые классы требуют особой обработки.

Обычно это классы, которые имеют какое-то отношение к файлам и соединениям (к db или только к сокетам). Последнее требуется, потому что базовая ОС требует, чтобы этот ресурс был явно освобожден (как правило).

В Java 8 был представлен Autoclosable , и он решает некоторые проблемы, но в конечном итоге вам нужно быть осторожным.

Вот пример для сканера с автоблокируемый:

File file = new File("filename here");
try (Scanner in = new Scanner(file)) {
    // do something here, note you dont need close as it is autoclosable
}
0 голосов
/ 29 мая 2020

Обычно, когда вы создаете Scanner, вам нужно закрыть , когда он вам больше не нужен.

Класс Scanner имеет несколько , перегруженные конструкторы, каждый из которых принимает разные типы аргументов. Существует конструктор, который принимает аргумент File. Существует конструктор, который принимает аргумент Path. И есть конструктор, который принимает аргумент InputStream. Чтобы ваша программа Java принимала ввод от пользователя через клавиатуру компьютера, вы используете конструктор, который принимает InputStream, например:

Scanner scanner = new Scanner(System.in);

Это потому, что stati c член in класса java.lang.System имеет тип InputStream. Вы должны думать о System.in как об инкапсулировании клавиатуры на вашем компьютере. Если вы закроете System.in, это будет похоже на закрытие клавиатуры, а этого делать не следует.

Теперь Eclipse IDE недостаточно умен, чтобы понять, что ваш код создает Scanner, который, по сути, заключает в себе клавиатуру компьютера (и поэтому не должен быть закрыт). Eclipse знает только, что любой Scanner, который вы создаете, должен в конечном итоге быть закрыт, и поскольку ваш код не закрывает Scanner, который вы создали, Eclipse отображает предупреждение, которое вы не сделали. закрыл созданный вами Scanner. В отображаемом предупреждении вам предлагаются три предложения о том, как избавиться от предупреждения. Первые два относятся к аннотации, которую вы можете добавить, а именно

@SuppressWarnings("resource")

Третье предложение требует, чтобы вы изменили конфигурацию Eclipse . Вы делаете это, выбирая пункт Preferences в меню Window , которое появляется в верхней части Eclipse IDE. В окне Preferenes выберите Java> Compiler> Errors / Warnings и измените настройку Resource leak на Игнорировать, как показано на следующем снимке экрана:

Eclipse preferences window

Однако обратите внимание, что этот параметр конфигурации применяется к всем ресурсам, а не только Scanner, поэтому, если вы откроете обычный файл в своем java код и не закрывайте его, Eclipse не предупредит вас.

Лично я просто игнорирую предупреждение, так как знаю, что не должен закрывать Scanner, созданный с помощью System.in или добавляю аннотацию.

...