Подтвердить что ты не робот

Try-with-resources при вызове супер-конструктора

Есть ли хороший способ использовать try-with-resources при открытии InputStream в конструкторе, а затем передать это супер-конструктору?

В основном я хочу сделать следующее:

public class A {
    public A(InputStream stream) {
        // Do something with the stream but don't close it since we didn't open it
    }
}

public class B {
    public B(File file) {
        // We open the stream so we need to ensure it properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            super(new FileInputStream(file));
        }
    }
}

Но, конечно, поскольку super должен быть первым утверждением в конструкторе, это недопустимо. Есть ли хороший способ достичь этого?

4b9b3361

Ответ 1

Рассмотрите возможность использования статического метода factory вместо прямого использования конструктора. Создайте как минимум B конструктор private и создайте такой метод, как

private B(InputStream is) {
    super(is);
    // Whatever else is needed
}

public static B newInstance(File file) {
    B result;
    try (FileInputStream stream = new FileInputStream(file)) {
        result = new B(stream);
    }
    // Further processing
    return result;
}

Ответ 2

Еще один способ:

public class A {
    protected A(){
        // so he can't be called from the outside, subclass ensure that init is done properly.
    }

    public A(InputStream stream) {
        init(stream);
    }
    // not be able to call it from outside
    protected final init(InputStream is){
        //here goes the code
    }
}

public class B {
    public B(File file) {
        // We open the stream so we need to ensure it properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            init(stream);
        }
    }
}

Я размещаю это здесь как возможный ответ, однако здесь я замираю:

  • Вы можете обновить код
  • Вы перемещаете код конструктора в метод init, благодаря защищенному пустому конструктору arg, только подклассы должны обрабатывать вызов для инициализации должным образом. Некоторые могут видеть, что это не так хорошо спроектировано. Моя точка зрения заключается в том, что как только вы подклассифицируете что-то, вам нужно больше узнать об этом, просто когда вы просто используете его.

Ответ 3

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

public class B {
    private static InputStream file2stream(File f){
        // We open the stream so we need to ensure it properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            return stream;
        }catch(/*what you need to catch*/){
             //cleanup
             // possibly throw runtime exception
        }
    }
    public B(File file) {
        super(file2stream(file))
    }
}