【问题标题】:Stream closed and not reopened - Java流已关闭且未重新打开 - Java
【发布时间】:2016-12-12 22:48:02
【问题描述】:

我有一个简单的“家庭作业”要做,但我发现输入流的关闭有一点问题。 简而言之,我必须在 Java 中创建一个联系人“列表”应用程序,以便以正确的方式使用多态性。所以我有一个类 Contact 和一个子类 Private(联系人)。在这两个类中都有一个修改方法来更改变量的值。

public void modify() throws IOException {
    System.out.println("Previously name: " + name);
    System.out.println("Insert new name");
    try(InputStreamReader ir = new InputStreamReader(System.in);    
    BufferedReader in = new BufferedReader(ir) ) {  
        name= in.readLine();
        System.out.println("You've changed the name to: "+ name);                       
    System.out.println("Previously surname: " + surname);
    System.out.println("Insert new surname");
        surname= in.readLine();
        System.out.println("You've changed the surname to: "+ surname);                         
    System.out.println("Previously e-mail: " + email);
    System.out.println("Insert new e-mail");
        email = in.readLine();
        System.out.println("You've changed the e-mail to: "+ email);    }                   
}

这是不会产生问题的 Contact 方法

@Override 
public void modify() throws IOException {
    super.modifica();
    System.out.println("Numero di cellulare precedente: " + cell);
    System.out.println("Inserire nuovo numero");
    try (InputStreamReader ir = new InputStreamReader(System.in);   
    BufferedReader in = new BufferedReader(ir)) {
        cell = in.readLine();
        System.out.println("Hai cambiato il numero in: "+ cell);                        
    System.out.println("Contatto skype precedente: " + skype);
    System.out.println("Inserire nuovo contatto");
        skype = in.readLine();
        System.out.println("Hai cambiato il contatto in: "+ skype);                         
}   
}

相反,这是 Private 中方法的覆盖。 主要是创建一个 Private 对象并调用 modify 方法。我可以毫无问题地插入姓名、姓氏和电子邮件,然后该方法由于流已关闭而引发 IO 异常。 我不明白为什么我会遇到这种问题。我认为在第一个代码中尝试使用资源关闭了流,但随后在第二个代码中通过另一个尝试使用资源打开了它。可能我的想法有问题。

【问题讨论】:

标签: java stream overriding try-with-resources


【解决方案1】:

您的问题确实是由于关闭 new InputStreamReader(System.in) 的 try-with-resource 语句在幕后关闭了 System.in 的底层输入流(inpublic staticSystem 字段) 这样在您的 modify 方法中 System.in 已经关闭,然后无法再读取这就是您收到此异常的原因。

【讨论】:

  • ... 并且流 System.in 不能被应用程序重新打开
  • 是否需要删除试试?因为我在书中读到,尽快关闭流很重要,并且作者建议使用 try with resource 来做到这一点。
  • 使用 try-with-resources 语句确实是一个很好的做法,但不是在这里,因为你真正关闭的唯一资源不能被关闭,所以你不能在这里使用它
  • 在这种情况下我能做些什么来避免内存浪费?
  • 让 GC 完成它的工作
【解决方案2】:

如果你用CloseShieldInputStream 包裹System.in,你仍然可以使用try-with-resources

我还建议使用Scanner 而不是InputStreamReaderBufferedReader,因为它很简单:

import java.util.Scanner;
import org.apache.commons.io.input.CloseShieldInputStream;

public class Contact {

    protected String name;
    protected String surname;
    protected String email;

    public void modify() throws IOException {
        System.out.println("Previously name: " + name);
        System.out.println("Insert new name");
        try (Scanner sc = new Scanner(new CloseShieldInputStream(System.in))) {
            name = sc.nextLine();
            System.out.println("You've changed the name to: " + name);
            System.out.println("Previously surname: " + surname);
            System.out.println("Insert new surname");
            surname = sc.nextLine();
            System.out.println("You've changed the surname to: " + surname);
            System.out.println("Previously e-mail: " + email);
            System.out.println("Insert new e-mail");
            email = sc.nextLine();
            System.out.println("You've changed the e-mail to: " + email);
        }
    }
}

public class Private extends Contact {

    private String cell;
    private String skype;

    @Override
    public void modify() throws IOException {
        super.modify();
        System.out.println("Numero di cellulare precedente: " + cell);
        System.out.println("Inserire nuovo numero");
        try (Scanner sc = new Scanner(new CloseShieldInputStream(System.in))) {
            cell = sc.nextLine();
            System.out.println("Hai cambiato il numero in: " + cell);
            System.out.println("Contatto skype precedente: " + skype);
            System.out.println("Inserire nuovo contatto");
            skype = sc.nextLine();
            System.out.println("Hai cambiato il contatto in: " + skype);
        }
    }
}

另见:Closing BufferedReader and System.in

【讨论】: