S2095 on Scanner constructors where close is not needed

  • Windows 10, IntelliJ IDEA plugin SonarLint 10.8.1.79205

java.util.Scanner has some constructors that don’t need closing. For example, you may be using an existing InputStream that is already being closed, in which case Scanner is merely a wrapper that closes its underlying stream. As far as I know, it allocates no resources of its own; which is why the AutoCloseable interface is ambiguous by definition, as some users may believe that everything AutoCloseable needs to be closed, but that doesn’t seem to be so. Here is a comment criticizing the rule: Reddit - Dive into anything

In this example, only the FileInputStream is created that SonarLint should care about (it correctly interprets this when it’s wrapped in a Scanner). The creation of Scanner itself is no reason to close it.

Another example is a String constructor that uses StringReader. It supports close(), which merely makes the instance null (to prevent it from being used), but there is no resource de-allocation, GC seems to do all the work anyway. As you can see on SO, this becomes a self-proving loop where people cite SonarLint as the only reason for why it should be closed: java.util.scanner - Java Scanner with string input should be closed? - Stack Overflow

I’m pleasantly surprised that System.in is already considered to be an exception here; so you can just continue with more exceptions to this rule. All Scanner constructors need to be considered individually; for example Path that allocates a Files.newInputStream(source) internally definitely does need closing, because it’s a new resource allocation.

// Correct usage without close, no problem detected
new Scanner(System.in);
// False positive
new Scanner("test");
FileInputStream fileInputStream = new FileInputStream("test.txt");
try (fileInputStream) {
    // False positive
    new Scanner(fileInputStream);
}
// Correct usage, no problem detected
try (Scanner scanner = new Scanner(new FileInputStream("test.txt"))) {
}

Hi @vodoc82730 ,

Thanks for your report!

I think the point where the circular argumentation is resolved is that the definition of the AutoCloseable interface says that the instance can hold ressources, and close is called to free them. Which implies: if the interface is implemented, then close should be called. Whether the implementation really holds ressources and the close method really does anything is an implementation detail that we cannot know in the general case and should not care about.

That being said, I think it’s indeed not convenient for developers to be forced to use close when a stream is merely a wrapper stream. Or even wrong if we don’t want the stream to be closed (you mentioned the use of System.in as an example).

So I think we should make an exception for AutoCloseables from the standard library that are only wrappers, such as Scanner, StringReader or FilterInputStream. I created a ticket for that here.

Cheers,
Marco

1 Like