Suppose I have 3 Scanner instances which I want to close.
I could do
sc.close()
for each of the Scanners.
Or I could do something like
for (Scanner sc: new Scanner[]{sc1,sc2,sc3}) { sc.close(); }
Is there any shorter way of doing this with Java 8?
Something similar to?
{sc1,sc2,sc3}.forEach((sc) -> sc.close());
Since Java 7 you should use try-with-resources
try(Scanner sc1 = new Scanner(""); Scanner sc2 = new Scanner(""); Scanner sc3 = new Scanner("")){ } //all scanners get closed implicitly
So you don't need any code at all.
The problem with all for-each or stream constructs is, that - theoretically - if the first close()
fails with an exception on invoking the underlying source's close()
method, the following scanners won't get closed. The Scanner.close()
implementation catches any IOException, but no other exception that may occur.
The try-with-resources construct deals with that, the loops don't.
EDIT: While your question targeted at a more general approach, the above solution was a response to your particular problem: to deal with AutoCloseable
resources, which should in any case be used with the try-with-resources construct, requiring no special treatment of the close method at all (= shortest solution to your particular problem).
Regarding the more general question about dealing with arbitrary items (which are no resources), Java has at least two options:
Creating a List from an Array/Varargs and iterate over it
for(YourItemType item : Arrays.asList(your,items,here)) { //do something }
Creating a Stream from an Array/Varargs and apply functions to it
Stream.of(your,items,here).forEach(item -> { doSomething});
Of course the "doSomething" can be replaced with a method reference
Stream.of(your,items,here).forEach(this::myMethod); ... void myMethod(YourItemType item){ //doSomething }
The problem with that approach is, that checked exception have to be dealt with explicitly in lambda expressions. Lets take the above example and let myMethod
throw a checked exception
void myMethod(YourItemType item) throws Exception
in that case your stream statement would have to look like
Stream.of(your,items,here).forEach(item -> { try { myMethod(item); } catch (Exception e){ //omit or throw new RuntimeException(e); };
This doesn't look that nice. But we could put the lambda body in a separate method
void myMethodQuietly(YourItemType item) { try { myMethod(item); }catch(Exception e){ //omit or throw new RuntimeException(e); } } Stream.of(your,items,here).forEach(this::myMethodQuietly);
This approach may be of interest to your particular resource problem. We can put all this into a CompositeAutoCloseable
that takes resources created outside the class that all should be closed safely on invocation of 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 } } }
And once you have such a helper class, you can use it again with try-with-resources.
try(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) { //do something }
I leave it up to you to decide if this makes sense compared to the inital solution ;)
If instantiation is separated from disposal, use Guava's com.google.common.io.Closer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With