Ответ 1
Начиная с Java 7 вы должны использовать try-with-resources
try(Scanner sc1 = new Scanner("");
Scanner sc2 = new Scanner("");
Scanner sc3 = new Scanner("")){
}
//all scanners get closed implicitly
Таким образом, вам совсем не нужен код.
Проблема со всеми конструкциями for-each или stream заключается в том, что - теоретически - если первый close()
завершился с ошибкой при вызове метода исходного метода close()
, следующие сканеры не будут закрыты. Реализация Scanner.close()
допускает любое исключение IOException, но не может быть другого исключения.
Конструкция try-with-resources имеет дело с этим, петли этого не делают.
EDIT. Хотя ваш вопрос был нацелен на более общий подход, вышеупомянутое решение было ответом на вашу конкретную проблему: для работы с ресурсами AutoCloseable
, которые в любом случае должны использоваться с try-with-resources, не требуя специальной обработки метода close (= кратчайшее решение вашей конкретной проблемы).
Что касается более общего вопроса о работе с произвольными элементами (которые не являются ресурсами), у Java есть как минимум два варианта:
Создание списка из массива /Varargs и его повторение
for(YourItemType item : Arrays.asList(your,items,here)) {
//do something
}
Создание потока из массива /Varargs и применение к нему функций
Stream.of(your,items,here).forEach(item -> { doSomething});
Конечно, "doSomething" можно заменить ссылкой на метод
Stream.of(your,items,here).forEach(this::myMethod);
...
void myMethod(YourItemType item){
//doSomething
}
Проблема с этим подходом заключается в том, что проверенное исключение должно рассматриваться явно в лямбда-выражениях. Давайте рассмотрим приведенный выше пример и пусть myMethod
вытащите исключенное исключение
void myMethod(YourItemType item) throws Exception
в этом случае ваш оператор потока должен выглядеть как
Stream.of(your,items,here).forEach(item -> {
try {
myMethod(item);
} catch (Exception e){
//omit or throw new RuntimeException(e);
};
Это не выглядит так хорошо. Но мы могли бы поместить тело лямбда в отдельный метод.
void myMethodQuietly(YourItemType item) {
try {
myMethod(item);
}catch(Exception e){
//omit or throw new RuntimeException(e);
}
}
Stream.of(your,items,here).forEach(this::myMethodQuietly);
Этот подход может представлять интерес для вашей конкретной проблемы с ресурсами. Мы можем поместить все это в CompositeAutoCloseable
, который берет ресурсы, созданные вне класса, которые должны быть безопасно закрыты при вызове close()
public class CompositeAutoCloseable implements AutoCloseable {
private List<Closeable> resources;
public CompositeAutoCloseable(Closeable... resources) {
this.resources = Arrays.asList(resources);
//you could use a stream here too
}
@Override
public void close() {
this.resources.stream().forEach(this::closeQuietly);
}
void closeQuietly(Closeable res) {
if(res == null) {
return;
}
try {
res.close();
}catch(Exception e){
//omit
}
}
}
И как только у вас будет такой вспомогательный класс, вы можете использовать его снова с помощью try-with-resources.
try(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) {
//do something
}
Я оставляю это для вас, чтобы решить, имеет ли это смысл по сравнению с внутренним решением;)