Given a Java function which uses a stream:
List<String> function(List<String> input) {
Stream<String> a = input.parallelStream();
Stream<String> b = a.map(c -> c.toString());
return b.collect(Collectors.toList());
}
Now, I want to control whether the mapping is performed by a parameter. Eclipse/the compiler gives me a warning: Resource leak: 'a' is never closed
List<String> function(List<String> input, boolean doMap) {
Stream<String> a = input.parallelStream(); // Resource leak: 'a' is never closed
Stream<String> b = doMap ? a.map(c -> c.toString()) : a;
return b.collect(Collectors.toList());
}
I can work around this with a try-with-resources statement:
List<String> function(List<String> input, boolean doMap) {
try (Stream<String> a = input.parallelStream()) {
Stream<String> b = doMap ? a.map(c -> c.toString()) : a;
return b.collect(Collectors.toList());
}
}
My question is: Why can there be resource leaks at all when I work with streams instead of for-loops? Why is there a resource leak if I only optionally add the mapping step? (Why isn’t there a resource leak in the first version of the function?) Is it “dangerous” to compose processing streams conditionally? What am I missing?
I summarize @Nikolas answer again in other words: There is no problem in Java, but the “problem” (if you want to call it that at all) is the variable. If a variable is declared to a type that implements AutoCloseable
(and Stream
does), Eclipse apparently reports a warning here that it is not being closed, if it does not find a call to close()
.
Since this error is Eclipse-related, it is likely that other checking tools will not fail on this and does not need to be “fixed” to pass such checks.
To my understanding, this shows a basic problem of Java, namely that it does not release the object on a variable as soon as it is no longer needed, but at some random point. With resources, that fails. Therefore, resources have to be tracked manually by the developer, where to close them, and manually to be closed. The Java runtime would (hypothetically) have to implement an approach like C++’s std::auto_ptr
, then this would not be necessary and if the last reference to the resource was deleted, this could be closed. But it's not like java "thinks".