英文:
Scanner object has a class attribute instead of in code initialisation
问题
今天,在编写服务器/客户端应用程序时,我遇到了Scanner
对象的问题。我已经解决了这个问题,但我不明白为什么我的解决方案能够解决这个问题。
起初,在我的应用程序中,在编译项目时(JAVA 8,eclipse),我遇到了一些内存泄漏警告,因为我正在使用Scanner
从用户那里获取输入,但没有关闭它。当我尝试关闭扫描器时,我的其他类抛出异常,如java.util.NoSuchElementException
。我了解到我遇到了与以下类似的问题:https://stackoverflow.com/questions/29053580/cannot-use-multiple-scanner-objects-in-java 但是发生在不同的类之间。当我在一个类中关闭一个扫描器时,另一个类(线程)中的扫描器无法执行(java.util.NoSuchElementException)。
我找到的解决这个问题的方法是将扫描器函数作为类函数成员:
public class ClientThread extends Thread {
private Scanner scanner;
/*一些代码*/
}
这样做后,我不再收到内存泄漏警告。
为什么将扫描器作为类成员解决了警告?是因为类的析构函数吗?
英文:
Today, I have encounter a problem with Scanner
object while programming a server/client application. I have solved the problem but I don't understand why my solution solved the problem.
At first, in my application I had some memory leak warning when compiling the project (JAVA 8, eclipse)
because I was using Scanner
to ask input from the user but didn't close it. When I try to close the scanner my other class where throwing exception like java.util.NoSuchElementException
. I learned that I had a similar problem to : https://stackoverflow.com/questions/29053580/cannot-use-multiple-scanner-objects-in-java but between classes. When I was closing a scanner in a class the other class (thread) scanner couldn't execute. (java.util.NoSuchElementException)
The solution I found to solve this problem was to put a Scanner function as a class function member:
public class ClientThread extends Thread {
private Scanner scanner;
/*some code*/
}
When doing so I lost my memory leak warning.
Why having the scanner as a class member solved the warning ? Is it because of the class destructor ?
答案1
得分: 0
通常,当你创建一个 Scanner
对象时,在你不再需要它时需要进行 关闭操作。
Scanner
类有多个重载的构造函数,每个构造函数都接受不同类型的参数。有一个构造函数接受一个 File
参数,另一个接受一个 Path
参数,还有一个构造函数接受一个 InputStream
参数。为了使你的 Java 程序能够从用户通过计算机键盘输入,你可以使用接受 InputStream
参数的构造函数,示例如下:
Scanner scanner = new Scanner(System.in);
这是因为类 java.lang.System
的静态成员 in
具有类型 InputStream
。你可以将 System.in
视为封装了计算机键盘的输入。如果你关闭了 System.in
,就像关闭了键盘一样,这是不应该做的。
然而,Eclipse IDE 并不足够智能,不能意识到你的代码创建的 Scanner
本质上封装了计算机键盘(因此不应该被关闭)。Eclipse 只知道你创建的任何 Scanner
最终应该被关闭,因为你的代码没有关闭你创建的 Scanner
,所以 Eclipse 显示一个警告,提示你没有关闭你创建的 Scanner
。在显示的警告中,有三个建议可以消除这个警告。前两个建议涉及到一个你可以添加的注解,即
@SuppressWarnings("resource")
第三个建议需要你更改 Eclipse 的配置。你可以通过选择 Eclipse IDE 顶部出现的 Window 菜单中的 Preferences 选项来进行配置。在 Preferences 窗口中,选择<tt>Java > Compiler > Errors/Warnings</tt>,然后将 Resource leak 设置更改为<tt>Ignore</tt>,如下面的屏幕截图所示:
然而需要注意的是,此配置设置适用于所有资源,不仅仅是 Scanner
,所以如果你在你的 Java 代码中打开了一个普通文件并且没有关闭它,Eclipse 不会警告你。
就个人而言,我通常忽略这个警告,因为我知道不应该关闭使用 System.in
创建的 Scanner
,或者我会添加一个注解。
英文:
Usually, when you create a Scanner
, you need to close it once you no longer need it.
The Scanner
class has several, overloaded constructors where each one takes a different type of argument. There is a constructor that takes a File
argument. There is a constructor that takes a Path
argument. And there is a constructor that takes a InputStream
argument. In order for your Java program to accept input from the user, via the computer keyboard, you use the constructor that takes an InputStream
like so:
Scanner scanner = new Scanner(System.in);
This is because the static member in
of class java.lang.System
has type InputStream
. You should think of System.in
as encapsulating the keyboard on your computer. If you close System.in
, it's like closing your keyboard and that is something you shouldn't do.
Now the Eclipse IDE is not smart enough to realize that your code is creating a Scanner
that essentially encapsulates the computer keyboard (and therefore should not be closed). Eclipse only knows that any Scanner
that you create should eventually be closed and since your code does not close the Scanner
you created, Eclipse displays a warning that you haven't closed a Scanner
that you created. In the displayed warning you are offered three suggestions on how to get rid of the warning. The first two refer to an annotation that you can add, namely
@SuppressWarnings("resource")
The third suggestion requires you to change the Eclipse configuration. You do this by selecting the Preferences item of the Window menu that appears at the top of the Eclipse IDE. In the Preferenes window, select <tt>Java > Compiler > Errors/Warnings</tt> and change the Resource leak setting to <tt>Ignore</tt> as shown in the following screen capture:
Note however, that this configuration setting applies to all resources, not just Scanner
, so if you open a regular file in your java code and don't close it, Eclipse will not warn you.
Personally, I simply ignore the warning since I know that I should not close a Scanner
created with System.in
or I add an annotation.
答案2
得分: 0
尽管 Java 通常会在您离开作用域时自动释放内存,但某些类需要特殊处理。
一般来说,这些类与文件和连接有关(可能是到数据库或套接字)。 后者是必需的,因为底层操作系统要求显式释放这些资源(通常情况下)。
在 Java 8 中引入了 Autoclosable 来解决其中一些问题,但最终您仍然需要小心处理。
以下是使用自动关闭的 Scanner 的示例:
File file = new File("在此处输入文件名");
try (Scanner in = new Scanner(file)) {
// 在此处进行操作,注意不需要关闭,因为它是自动可关闭的
}
英文:
Although Java usually auto-release the memory when you leave the scope some classes require special treatment.
Generally these are classes who has something to do with files and connections (to db or just sockets).
The latter is required because the underlying OS requires those resource to be explicitly released (in general).
In the Java 8 there was introduced Autoclosable and it solves some of the problems but ultimately you need to be careful.
Here is an example for Scanner with 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
}
专注分享java语言的经验与见解,让所有开发者获益!
评论