Depuis Java 7, vous devriez utiliser try-with-resources
try(Scanner sc1 = new Scanner("");
Scanner sc2 = new Scanner("");
Scanner sc3 = new Scanner("")){
}
//all scanners get closed implicitly
Vous n'avez donc pas besoin de code du tout.
Le problème avec toutes les constructions for-each ou stream est que - théoriquement - si le premier close()
échoue avec une exception lors de l'invocation de la source sous-jacente. close()
les scanners suivants ne seront pas fermés. Le site Scanner.close()
attrape toute exception IOException, mais aucune autre exception qui pourrait se produire.
La construction try-with-resources s'en occupe, les boucles ne le font pas.
EDITAR : Alors que votre question visait une approche plus générale, la solution ci-dessus était une réponse à votre problème particulier : faire face à AutoCloseable
qui, en tout état de cause, doivent être utilisées avec l'outil de gestion des ressources. essayer avec les ressources qui ne nécessite aucun traitement particulier de la méthode de fermeture (= solution la plus courte pour votre problème particulier).
En ce qui concerne la question plus générale du traitement des éléments arbitraires (qui ne sont pas des ressources), Java a au moins deux options :
Création d'une liste à partir d'un tableau/de variables et itération sur cette liste
for(YourItemType item : Arrays.asList(your,items,here)) {
//do something
}
Créer un flux à partir d'un tableau/Varargues et lui appliquer des fonctions
Stream.of(your,items,here).forEach(item -> { doSomething});
Bien sûr, le "doSomething" peut être remplacé par une référence de méthode
Stream.of(your,items,here).forEach(this::myMethod);
...
void myMethod(YourItemType item){
//doSomething
}
Le problème avec cette approche est que les exceptions vérifiées doivent être traitées explicitement dans les expressions lambda. Prenons l'exemple ci-dessus et laissons myMethod
lancer une exception vérifiée
void myMethod(YourItemType item) throws Exception
dans ce cas, votre déclaration de flux devrait ressembler à ceci
Stream.of(your,items,here).forEach(item -> {
try {
myMethod(item);
} catch (Exception e){
//omit or throw new RuntimeException(e);
};
Ça n'a pas l'air si bien que ça. Mais nous pourrions mettre le corps lambda dans une méthode séparé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);
Cette approche peut s'avérer intéressante pour votre problème particulier de ressources. Nous pouvons mettre tout cela dans un CompositeAutoCloseable
qui prend des ressources créées en dehors de la classe et qui doivent toutes être fermées en toute sécurité lors de l'invocation de la fonction 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
}
}
}
Et une fois que vous avez une telle classe d'aide, vous pouvez l'utiliser à nouveau avec try-with-resources.
try(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) {
//do something
}
Je vous laisse le soin de décider si cela a du sens par rapport à la solution initiale ;)
1 votes
stackoverflow.com/questions/24390463/
10 votes
Pour répondre à la question générale :
Stream.of(sc1, sc2, sc3).forEach(Scanner::close);
mais pour ce cas spécifique écouter Gerald Mücke