Поток закрыт и не открыт повторно - Java

У меня есть легкая «домашняя работа», но я обнаружил небольшую проблему с закрытием входного потока. Проще говоря, мне нужно создать приложение «список контактов» на 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);    }                   
}

Это контактный метод, который не создает проблем

@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. В основном я создаю частный объект и вызываю метод модификации. Я могу без проблем вставить имя, фамилию и адрес электронной почты, затем метод выдает исключение ввода-вывода, потому что поток закрыт. Я не могу понять, почему у меня такая проблема. Я думаю, что поток закрывается попыткой с ресурсами в первом коде, но затем открывается во втором коде другой попыткой с ресурсами. Наверное, что-то в моей идее не так.


person Bondye    schedule 06.08.2016    source источник
comment
Возможно, вам стоит узнать о java.util.Scanner. Вы можете начать здесь: stackoverflow.com/a/11871792/4791599   -  person Markus Mitterauer    schedule 07.08.2016
comment
Благодарю вас! Есть ли различия в возможностях и администрировании памяти между Scanner и BufferedReader?   -  person Bondye    schedule 10.08.2016
comment
Возможный дубликат закрытия BufferedReader и System.in   -  person Markus Mitterauer    schedule 12.08.2016


Ответы (2)


Ваша проблема действительно связана с оператором try-with-resource, который закрывает new InputStreamReader(System.in), который за сценой закрывает также базовый входной поток, который является System.in (in является полем public static System), так что в вашем методе modify System.in уже закрыт, а затем больше не может быть прочитан, поэтому вы получаете это исключение.

person Nicolas Filotto    schedule 06.08.2016
comment
... и поток System.in не может быть повторно открыт приложением. - person Markus Mitterauer; 06.08.2016
comment
Нужно ли удалять попытку? Поскольку я читал в книге, важно закрыть поток как можно скорее, и автор предлагает использовать для этого попытку с ресурсом. - person Bondye; 06.08.2016
comment
использование оператора try-with-resources действительно является хорошей практикой, но не здесь, поскольку единственный ресурс, который вы действительно закрываете, не должен быть закрыт, поэтому вы не можете использовать его здесь - person Nicolas Filotto; 07.08.2016
comment
Что я могу сделать, чтобы избежать потери памяти в этой ситуации? - person Bondye; 07.08.2016
comment
пусть GC делает свою работу - person Nicolas Filotto; 07.08.2016
comment
Благодарю вас! Урок н. 1: close() и try с ресурсами не нужны для освобождения памяти, используемой потоком. - person Bondye; 10.08.2016
comment
еще раз, это очень специфический вариант использования, в большинстве случаев использование оператора try-with-resource является правильным подходом. - person Nicolas Filotto; 10.08.2016
comment
Если мой ответ достаточно хорош, не стесняйтесь проголосовать за два, спасибо заранее - person Nicolas Filotto; 10.08.2016

Вы все еще можете использовать try-with-resources, если вы обернете System.in с CloseShieldInputStream.

Я бы также рекомендовал использовать Scanner вместо InputStreamReader и BufferedReader из-за его простоты:

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);
        }
    }
}

См. также: Закрытие BufferedReader и System.in

person Markus Mitterauer    schedule 12.08.2016