Reputation: 6176
I'm trying to migrate existing code to try with resource, but not sure how to deal when the closable resources are passed to other methods.
My main concern is how to prevent the developers from touching the method additionalMethod()
from closing the resource by mistake?
Maybe passing around closeable resources is not a good idea at all.
Example of the code:
class SomeClass {
void readMethod() {
try (Scanner scanner = new Scanner(new File("test.txt"))) {
additionalMethod(scanner);
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
}
void additionalMethod(Scanner scanner) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
// scanner.close() how to ensure no one does this by mistake?
}
}
Upvotes: 1
Views: 381
Reputation: 29068
how to prevent the developers from touching the method
additionalMethod()
from closing the resource by mistake?Maybe passing around closeable resources is not a good idea at all.
Maybe passing around closeable resources is not a good idea at all.
There's nothing bad with opening the stream in one method, where it's wrapped in try-with-resources in handing it out to another method, like in your example.
If you call close()
on a stream multiple times, nothing would fail. The first call would close the stream, the subsequent calls would have no effect.
Here's a quote from the documentation of the Reader
interface:
Closes the stream and releases any system resources associated with it. Once the stream has been closed, further
read()
,ready()
,mark()
,reset()
, orskip()
invocations will throw an IOException. Closing a previously closed stream has no effect.
Hovewhever, using Scanner
for dialing with files is not the most performant approach, you can use FileReader
wrapped with a BufferedReader
which has a greater capacity of the buffer than Scanner (8192
vs 1024
).
public void readMethod(String fileName) {
try (var reader = new BufferedReader(new FileReader(fileName))) {
additionalMethod(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
public void additionalMethod(BufferedReader reader) throws IOException {
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close(); // it's pointless but not harmful
reader.close(); // it's pointless but not harmful
}
Methods for handling Input/Output became way learner if you're using NIO.2 API.
That how these two methods could be reimplemented using [Files.lines()
] which produces a stream of lines:
public void readMethod(String fileName) {
try (Stream<String> stream = Files.lines(Path.of(fileName), Charset.defaultCharset())) {
additionalMethod(stream);
} catch (IOException e) {
e.printStackTrace();
}
}
public void additionalMethod(Stream<String> stream) {
stream.forEach(System.out::println);
}
Upvotes: 1
Reputation: 71
NOTE: In the example you give, all is happening in the same class. Hence, it is not that much of a problem. Problem happens when you pass it to an alien method. (Method specified in another class)
public class Wrapper{ //probabily there is better name depending on the domain, application and context.
private final Scanner underlyingScannner;
public Wrapper(Scanner scanner){
this.underlyingScannner = scanner;
}
public boolean hasNext(){
return underlyingScannner.hasNext();
}
public String nextLine(){
return underlyingScannner.nextLine();
}
}
If you have an interface which the closeable objects implements and you can use in an alien method. You can pass using that interface instead of creating an explicit wrapper. For instance;
public class ACloseableObject implements ObjectInterface, AutoCloseable{ ... }
In this case, you can pass using the reference of type ObjectInterface. (You do not need to create a seperate wrapper because of the fact that the closeable object already implements ObjectInterface and this interface do not expose close operation)
NOTE: In this case, the object could be casted into AutoCloseable.
final AutoCloseable casted = (AutoCloseable)objectInterfaceReference;
Upvotes: 1
Reputation: 44414
Passing closeable resources around is fine. Let’s look at some examples in Java SE:
As for how to prevent other methods from closing a closeable resource, you may want to use assertions in the calling code:
void readMethod() {
try (ReadableByteChannel channel = FileChannel.open(Path.of("test.txt"));
Scanner scanner = new Scanner(channel)) {
additionalMethod(scanner);
assert channel.isOpen() :
"additionalMethod was not supposed to close the Scanner!";
} catch (IOException e) {
e.printStackTrace();
}
}
void additionalMethod(Scanner scanner) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
}
Upvotes: 1