2016-05-04 5 views
37

Предположим, у меня есть 3 экземпляра сканера, которые я хочу закрыть.Самый короткий способ перебора не-списка?

я мог бы сделать

sc.close() 

для каждого из сканеров.

Или я мог бы сделать что-то вроде

for (Scanner sc: new Scanner[]{sc1,sc2,sc3}) { 
    sc.close(); 
} 

Есть ли более короткий способ сделать это с помощью Java 8?

Нечто похожее на?

{sc1,sc2,sc3}.forEach((sc) -> sc.close()); 
+1

http://stackoverflow.com/questions/24390463/java-8-stream-and-operation-on-arrays – Tschallacka

+10

Чтобы ответить на общий вопрос: 'Stream.of (sc1, sc2, sc3) .forEach (Scanner :: close); ', но для этого конкретного случая [послушайте Джеральда Мюке] (http://stackoverflow.com/a/37023624/2711488) – Holger

ответ

73

Поскольку Java 7 вы должны использовать примерочный с-ресурсами

try(Scanner sc1 = new Scanner(""); 
    Scanner sc2 = new Scanner(""); 
    Scanner sc3 = new Scanner("")){ 

} 
//all scanners get closed implicitly 

Так что вам не нужны какая-либо кода.

Проблема со всеми конструкциями для каждого или потока состоит в том, что - теоретически - если первый close() сбой исключается при вызове метода базового источника close(), следующие сканеры не будут закрыты. Реализация Scanner.close() улавливает любое исключение IOException, но не может быть другого исключения.

Консоль try-with-resources имеет дело с этим, петли этого не делают.


EDIT: В то время как Ваш вопрос направлен на более общий подход, указанное решение было ответом на вашей конкретной проблемы: иметь дело с AutoCloseable ресурсов, которые в любом случае должны быть использованы с пытаясь угадать с-ресурсами, не требуя специальной обработки метода закрытия вообще (= кратчайшее решение вашей конкретной проблемы).

Что касается более общего вопроса о работе с произвольными элементами (которые нет ресурсов), Java имеет по крайней мере два варианта:

Создание списка из массива/списков параметров и перебрать его

for(YourItemType item : Arrays.asList(your,items,here)) { 
    //do something 
} 

Создание потока из массива/списков параметров и применять функции к нему

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(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) { 
    //do something 
} 

Я оставляю это до вас, чтобы решить, если это имеет смысл, по сравнению с щётками раствора;)

+1

Этот ответ, кажется, имеет для меня наибольший смысл. Использование «AutoCloseable» вместо жесткого потока для явного закрытия «Сканера» кажется наиболее естественным решением. – Mena

+0

Обратите внимание, что try-with-resource по-прежнему на самом деле не на 100% безопасен. Вот простой пример из C#, где это может быть проблематично с соответствующей конструкцией: http://stackoverflow.com/a/21123756/1348195 –

+6

@Benjamin Gruenbaum: этот пост использует множество конструкций C#, которые не существуют в Ява. Как правило, это не входит в код *, используя * 'Сканер', чтобы исправить возможные ошибки в конструкторе класса« Сканер ». Конечно, это не «100% безопасно», но ничего нет. Как вы защищаете кого-то, вытаскивая вилку? – Holger

-1

Хотя иногда корреляция между длиной коды и его качеством, что не является хорошим критерий использования для выбора кода.

я бы, вероятно, использовать и делать с переменным числом аргументов это что-то вроде:

private void closeScanner(Scanner... scanners) { 
    // Faff around with Java 8 in here if you like. 
    for (Scanner s : scanners) { 
     s.close(); 
    } 
} 

    // Some code. 
    closeScanner(s, t, u); 
+0

Исключение безопасности безопасности – Basilevs

+0

@basilevs - Scanner.close не генерирует исключений. – OldCurmudgeon

+0

@OldCurmudgeon: ну, он выбрасывает только непроверенные исключения. –

Смежные вопросы