简体   繁体   English

关闭在if语句中已初始化的PrintWriter对象

[英]Closing a PrintWriter Object that has been initialized in an if statement

This is probably a pretty basic question, but I am trying to make a Java method that executes a process and reads the inputstream created from that process and writes to a new file. 这可能是一个非常基本的问题,但是我正在尝试制作一个Java方法来执行一个流程,并读取从该流程创建的输入流并将其写入新文件。 I am using Runtime.getRuntime().exec(cmd[]) and I want to use different arguments for a specific index eg cmd[3] = "something" or cmd[3] = "something else". 我正在使用Runtime.getRuntime()。exec(cmd []),并且想对特定索引使用不同的参数,例如cmd [3] =“ something”或cmd [3] =“ somethingother”。 I am using a for loop to do this, but for the first index in my array of arguments for cmd[3] I want it to print to a new file with PrintWriter so I initialized it in an if statement after initializing it at the top of the for loop. 我正在使用for循环来执行此操作,但是对于cmd [3]的参数数组中的第一个索引,我希望它使用PrintWriter打印到新文件,因此在顶部将其初始化后在if语句中对其进行了初始化for循环。 It'll probably be easier if I just show the code so here you go: 如果仅显示代码,可能会更容易,在这里您可以:

public static synchronized void myMethod(String [] argument3, File file) throws IOException{

    String[] cmd = {"command", "argument 1", "argument 2"};
    PrintWriter fileWriter = null;
    Scanner fileScanner = null;
    int i;
    for(i = 0; i < argument3.length; i++){
        fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,true)));;
        cmd[3] = argument3[i];
        if(i == 0){
            fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,false)));
        }
        Process p = Runtime.getRuntime().exec(cmd);
        fileScanner = new Scanner(p.getInputStream());

        while(fileScanner.hasNextLine()){
            fileWriter.println(fileScanner.nextLine());
        }
        fileWriter.close();
        fileScanner.close();

    }

}

All of this works fine, but in eclipse I get a warning saying I have a resource leak where I initialize my PrintWriter in the if statement so I am just sort of curious as to why that is since I close them at the bottom of the for loop? 所有这些都可以正常工作,但是在eclipse中,我收到一条警告,说我在if语句中初始化PrintWriter时发生资源泄漏,因此我有点好奇为什么这样做,因为我在for的底部将它们关闭了环? I know it doesn't make too much of a difference since it works anyway I just want to try to cleanup my code properly. 我知道这并没有太大的区别,因为无论如何我都只想尝试正确清理我的代码。 Thanks in advance 提前致谢

The important thing to note is the 要注意的重要一点是

throws IOException

This can be thrown and if it is thrown, your resource will not be closed. 可以抛出该异常,如果抛出该异常,则不会关闭您的资源。 You should make sure that your resources get closed in ANY case, even if an exception is thrown. 即使抛出异常,也应确保在任何情况下都关闭资源。 Use... 采用...

try { ... } finally {   ... close here... } 

...for that. ...为了那个原因。 Imagine something bad happens, while your file is read. 想象一下,在读取文件时发生了一些不良情况。 The IOException is thrown and your close() statement is never called, which would be the dreaded resource leak mentioned by eclipse. 抛出IOException并且永远不会调用您的close()语句,这将是eclipse提到的可怕的资源泄漏

I get a warning saying I have a resource leak where I initialize my PrintWriter in the if statement. 我收到一条警告,说我在if语句中初始化PrintWriter的地方发生资源泄漏。

Here's the problem: 这是问题所在:

fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,true)));
if (i == 0) {
    fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,false)));
}
fileWriter.close();

The first time through the loop, when that condition holds, you're creating two PrintWriters , only the second of which is closed. 第一次循环时,当该条件成立时,您将创建两个PrintWriters ,其中只有第二个是关闭的。 You're simply discarding the first one. 您只是在丢弃第一个。 Instead, you could initialize it like this: 相反,您可以像这样初始化它:

fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file, i != 0)));

But that raises the question, why are you recreating the PrintWriter each time through the loop? 但这提出了一个问题,为什么每次循环都要重新创建PrintWriter Just create it once, outside of the loop. 只需在循环外创建一次即可。

The other problem is that none of your cleanup code is actually executed if an exception is thrown. 另一个问题是,如果引发异常,则实际上不会执行任何清理代码。 What you need is a try-catch-finally block, where you can guarantee that your cleanup code is executed. 您需要的是try-catch-finally块,您可以在其中保证执行清理代码。 If you're using at least Java 7, you can use try-with-resources , which will take care of all the cleanup for you automatically: 如果您至少使用Java 7,则可以使用try-with-resources ,它将自动为您进行所有清理:

void myMethod(String [] argument3, File file) throws IOException {
    String[] cmd = {"command", "argument 1", "argument 2"};
    try (PrintWriter fileWriter = new PrintWriter (file)) {
        for (int i = 0; i < argument3.length; i++) {
            Process process = Runtime.getRuntime().exec(cmd);
            try (Scanner fileScanner = new Scanner(process.getInputStream())) {
                cmd[3] = argument3[i];
                while (fileScanner.hasNextLine()) {
                    fileWriter.println(fileScanner.nextLine());
                }
            }
        }
    }
}

Basically, VM is complaning because the two inner objects are never closed. 基本上,VM正在抱怨,因为两个内部对象从未关闭过。

 for(i = 0; i < argument3.length; i++){
        fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,true)));;
        cmd[3] = argument3[i];
        if(i == 0){
            fileWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,false)));
        }
        Process p = Runtime.getRuntime().exec(cmd);
        fileScanner = new Scanner(p.getInputStream());

        while(fileScanner.hasNextLine()){
            fileWriter.println(fileScanner.nextLine());
        }
        fileWriter.close();
        fileScanner.close();

    }

You should basically separate the element definition like this: 您应该基本上将元素定义分开,如下所示:

for (i = 0; i < argument3.length; i++) {
FileOutputStream fos;    
    if (i == 0)
        fos = new FileOutputStream(file, false);
    else
        fos = new FileOutputStream(file, true);
    OutputStreamWriter osw = new OutputStreamWriter(osw);
    fileWriter = new PrintWriter(osw);
    // do the rest
    // and then...
    fileWriter.close();
    fileScanner.close();
    osw.close();
    fos.close();
}

That will remove the warning. 这将删除警告。

PS: As the previous answer suggests, moving .close methods to a finally block would be considered the best. PS:正如前面的答案所建议的那样,将.close方法移动到finally块将被认为是最好的。

Use try catch finally block and close your Scanner and PrintWriter in finally block since finally always executes: 使用try catch finally块,并在finally块中关闭ScannerPrintWriter ,因为finally始终执行:

public static synchronized void myMethod(String[] argument3, File file) {
        String[] cmd = { "command", "argument 1", "argument 2" };
        PrintWriter fileWriter = null;
        Scanner fileScanner = null;
        try {
            for (int i = 0; i < argument3.length; i++) {
                fileWriter = new PrintWriter(new OutputStreamWriter(
                        new FileOutputStream(file, true)));
                cmd[3] = argument3[i];
                if (i == 0) {
                    fileWriter = new PrintWriter(new OutputStreamWriter(
                            new FileOutputStream(file, false)));
                }
                Process p = Runtime.getRuntime().exec(cmd);
                fileScanner = new Scanner(p.getInputStream());

                while (fileScanner.hasNextLine()) {
                    fileWriter.println(fileScanner.nextLine());
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fileWriter.close();
            fileScanner.close();
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM