Ответ 1
Исключение из is.close() будет подавлено, и исключение из is.read() будет тем, которое распространяется вверх.
Мне интересно, будет ли нижеследующий код закрывать InputStream в окончательном блоке правильно
InputStream is = new FileInputStream("test");
try {
for(;;) {
int b = is.read();
...
}
} finally {
try {
is.close();
} catch(IOException e) {
}
}
Если исключение происходит во время is.read(), будет ли оно игнорироваться/подавляться, если исключение происходит во время is.close()?
Исключение из is.close() будет подавлено, и исключение из is.read() будет тем, которое распространяется вверх.
Лучший способ - использовать Java 7 и использовать try с ресурсами или сделать то же самое вручную и добавить исключение из закрытия как исключенное исключение.
Предварительная Java 7: Если вы выбрасываете свое собственное исключение, вы можете добавить в него исключение с нарушением, как это сделано в Java 7 (в вашем случае создайте поля List List, и вы получите исключения из операции закрытия и при работе с вашим исключением, посмотрите там тоже. Если вы не можете этого сделать, я не знаю ничего лучше, чем просто зарегистрировать его.
примеры: из Учебники Java
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
но лучшая форма:
static String readFirstLineFromFile(String path) throws IOException {
try (FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr)) {
return br.readLine();
}
}
Таким образом, даже если создание FileReader является успешным, но создание BufferedReader завершается с ошибкой (например, недостаточно памяти), FileReader будет закрыт.
спецификации Java 6 говорят
Если выполнение блока try завершается внезапно по любой другой причине R, тогда выполняется блок finally. Тогда есть выбор: Если окончательный блок завершается нормально, то оператор try внезапно завершается по причине R. Если блок finally завершается внезапно для разума S, то оператор try внезапно завершается по причине S (и причина R отбрасывается).
Итак, вы правы, вы потеряете исходное исключение.
Решение, вероятно, состоит в том, чтобы написать ваш блок finally настолько защитно, что это большой сюрприз (стоит размножаться), если блок finally завершится неудачей, чем если исключение выйдет из блока catch try.
Итак, например, если возможно, что поток может быть пустым при попытке закрыть его, проверьте его:
InputStream is = new FileInputStream("test");
try {
for(;;) {
int b = is.read();
...
}
} finally {
try {
if( is!=null ) {
is.close();
}
} catch(IOException e) {
}
}
В Java 7 решение Alpedar - это, конечно, путь.
Вы можете закрыть его с помощью IOUtils https://commons.apache.org/proper/commons-io/
public void readStream(InputStream ins) {
try {
//do some operation with stream
} catch (Exception ex) {
ex.printStackTrace();
} finally {
IOUtils.closeQuietly(ins);
}
}
С кодом, который вы отправили:
is.close()
выбрасывает IOException
, он отбрасывается и распространяется исходное исключение.is.close()
выбрасывает что-то другое (a RuntimeException
или Error
), оно распространяется и исходное исключение отбрасывается.С Java 7 правильный способ закрыть InputStream без потери исходного исключения состоит в использовании try-with-resources statement:
try (InputStream is = new FileInputStream("test")) {
for(;;) {
int b = is.read();
// ...
}
}
До появления Java 7 все, что вы делаете, просто отлично, за исключением того, что вы можете поймать все исключения вместо просто IOException
s.
Основываясь на вашем примере кода, если в точке int b = is.read();
возникает исключение, тогда исключение будет поднято выше цепочки вызовов.
Обратите внимание, что блок finally все равно будет выполняться, и если будет отклонено Inputstream
другое исключение, но это исключение будет "проглочено", что может быть приемлемым в зависимости от вашего варианта использования.
Изменить:
Основываясь на названии вашего вопроса, я бы добавил, что то, что у вас есть, на мой взгляд. Вы можете дополнительно добавить блок catch
, чтобы явно обрабатывать (или, возможно, обертывать) любое исключение в первом блоке try
, но также допустимо, чтобы любые исключения IO поднимались - это действительно зависит от вашего API. Это может быть или не быть приемлемым, чтобы позволить исключениям IO поднимать. Если это так, то что у вас получилось - если это не так, тогда вы можете обработать/обернуть исключение IO с чем-то более подходящим для вашей программы.
Как насчет следующего решения:
InputStream is = new FileInputStream("test");
Exception foundException=null;
try {
for(;;) {
int b = is.read();
...
}
} catch (Exception e){
foundException=e;
}
finally {
if(is!=null)
try {
is.close();
} catch(IOException e) {
}
}
//handle foundException here if needed
Если исключение происходит во время is.read(), будет ли оно игнорироваться/подавляться, если исключение происходит во время is.close()?
Да. У вас есть блок catch для исключения в close(), который не перебрасывает исключение. Ergo не размножается и не обновляется.
Это образец, который поможет понять вашу проблему, если вы объявите сканер в блоке try-catch, он предоставит компилятору предупреждение о том, что ресурс не закрыт. поэтому либо сделайте это локально, либо просто в try()
import java.util.InputMismatchException;
import java.util.Scanner;
class ScanInt {
public static void main(String[] args) {
System.out.println("Type an integer in the console: ");
try (Scanner consoleScanner = new Scanner(System.in);) {
System.out.println("You typed the integer value: "
+ consoleScanner.nextInt());
} catch (InputMismatchException | ArrayIndexOutOfBoundsException exception) {
System.out.println("Catch Bowled");
exception.printStackTrace();
}
System.out.println("----------------");
}
}