Do Java Lambda Expressions Utilize "Hidden" or Local Package Imports?
import
declarations are not meant to declare what classes your code is using; they just declare what to use to resolve unqualified identifiers. So if you are using the unqualified identifier Path
in your code you have to use import java.nio.file.Path;
to declare that it should get resolved to this qualified type. This is not the only way to resolve a name, by the way. Names can also get resolved through the class inheritance, e.g. if they match the simple name of an inherited member class.
If you are using a type implicitly without referring to its name you don’t need an import
statement, that’s not limited to lambda expressions, it is not even a special Java 8 feature. E.g. with
Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1)
you are already using the Path
type implicitly as it’s the return type of Paths.get
and a parameter type of Files.walk
, in other words, you are receiving an instance of java.nio.file.Path
and passing it to another method without referring to its type name, hence you don’t need an import
. Further you are calling a varargs method accepting an arbitrary number of FileVisitOption
instances. You are not specifying any, therefore your code will create a zero-length FileVisitOption[]
array and pass it to Files.walk
, again, without an import
.
With the improved type inference, there is another possibility to use a type without referring to its name, e.g. if you call:
Files.newByteChannel(path, new HashSet<>());
You are not only creating a zero length FileAttribute[]
array for the varargs parameter without referring to this type by name, you are also creating a HashSet<OpenOption>
without referring to the type OpenOption
by name. So this also doesn’t require neither, importing java.nio.file.attribute.FileAttribute
nor java.nio.file.OpenOption
.
So the bottom line is, whether you need an import
does not depend on the use of the type but whether you refer to it by its simple name (and there are more than one way to use a type without referring to it by name). In your second example you are referring to the name Path
in your method printPath(Path passedFilePath)
; if you change it to printPath(Object passedFilePath)
, everything will work again without an explicit import
of java.nio.file.Path
.
The difference is that in the second example, you declare a local variable Path passedFilePath
(as a method parameter). When you do this, you need an import
to tell the java compiler which type Path
you mean, because multiple packages can have a class with the same name. You might have noticed that when you create a variable List something
and ask the IDE to auto-create the import, most IDEs will usually ask you if you mean java.util.List
or java.awt.List
. You could also create an own class com.myorg.myproject.List
which would then be a third option.
In the first example the exact type of filePath
is determined by the type required by Paths.get(...).forEach
, so you don't need to tell the java compiler which class Path
you refer to.
By the way, you could omit the import in the second example, when you would rewrite the method signature as public void printPath(java.nio.file.Path passedFilePath)
. When providing a fully qualified class name, you don't need an import anymore because the class-name can not be ambiguous.
You might wonder "but why do I need an import or fully qualified name when there is only one class named Path
in the whole standard library and I don't have an own class of that name?" - remember that Java is designed for code re-usability. When your code is used in another project, that project might have such a class or might use a 3rd-party library which has and then your code would be ambiguous.