Are Java Lambda expressions expressions hidden or local packages?

This question is about the obvious “hidden” or local import of Java packages that seem to use lambda expressions.

The following code example compiles and works fine (it just lists the files in this directory):

package com.mbm.stockbot; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; public class Temp2 { public static void main(String[] args) { Temp2 t = new Temp2(); t.readDir(); } public void readDir() { try { Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1).forEach(filePath -> { if (Files.isRegularFile(filePath)) { System.out.println(filePath); } }); } catch (IOException e1) { e1.printStackTrace(); } } } 

Note that the filePath variable is an instance of Path , the implementation of which, I think, is contained in the java.nio.file.Path package, although there is no import for this package.

Now, if I make a small modification, say, refactoring a call to System.out.println using my own method:

 package com.mbm.stockbot; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class Temp2 { public static void main(String[] args) { Temp2 t = new Temp2(); t.readDir(); } public void readDir() { try { Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1).forEach(filePath -> { if (Files.isRegularFile(filePath)) { printPath(filePath); } }); } catch (IOException e1) { e1.printStackTrace(); } } public void printPath(Path passedFilePath) { System.out.println(passedFilePath); } } 

Now I have to "import" import java.nio.file.Path , otherwise I get a compiler error.

So my questions are:

  • If filePath really an instance of java.nio.file.Path , why don't I need to import it in the first example, and

  • If using a lambda expression imports "under the covers", then why do I need to add import when I create a method that takes an instance of Path as an argument?

The methods available for calling both filePath and passedFilePath are identical, which means that they are both instances of java.nio.file.Path .

+6
source share
4 answers

import declarations are not intended to declare classes used by your code; they simply declare what to use to resolve unqualified identifiers. Therefore, if you use the unqualified Path identifier in your code, you should use import java.nio.file.Path; to declare that it must be authorized for this qualified type. By the way, this is not the only way to resolve the name. Names can also be resolved through class inheritance, for example. if they match the simple name of the inherited member class.

If you use a type implicitly without referring to its name, you do not need an import statement that is not limited to lambda expressions; it is not even a special function of Java 8. For example. from

 Files.walk(Paths.get("C:/Users/mbmas_000/Downloads/SEC Edgar"), 1) 

you already use the Path type implicitly as its Paths.get return Paths.get and the Files.walk parameter Files.walk , in other words, you get an instance of java.nio.file.Path and pass it to another method without referring to its type name, so you don't need import . Next, you call the varargs method, which accepts an arbitrary number of instances of FileVisitOption . You do not specify any, so your code will create an array of FileVisitOption[] with zero length and pass it to Files.walk , again, without import .

With improved type inference, there is another possibility to use a type without reference to its name, for example. if you call:

 Files.newByteChannel(path, new HashSet<>()); 

You not only create an array with a zero length FileAttribute[] for the varargs parameter, without accessing this type by name, you also create a HashSet<OpenOption> without referring to the OpenOption type by name. So it also doesn’t require either import of java.nio.file.attribute.FileAttribute or java.nio.file.OpenOption .


So, the bottom line: whether you need import does not depend on the use of this type, but whether you refer to it by a simple name (and there are several ways to use a type without reference to it by name). In the second example, you refer to the Path name in your printPath(Path passedFilePath) method; if you change it to printPath(Object passedFilePath) , everything will work again without explicit import java.nio.file.Path .

+5
source

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 to import tell the java compiler that is typing Path , which means that several packages can have a class with the same name. You may have noticed that when you create the List something variable and ask the IDE to automatically create an import, most IDEs usually ask you if you have the value java.util.List or java.awt.List . You can also create your own class com.myorg.myproject.List , which then becomes the third option.

In the first example, the exact type of filePath is determined by the type required by Paths.get(...).forEach , so you do not need to specify the java compiler you are referring to class Path .

By the way, you can omit the import in the second example, when you rewrite the method signature as public void printPath(java.nio.file.Path passedFilePath) . When providing the full class name, you no longer need to import, because the class name cannot be ambiguous.

You may be wondering: "But why do I need to import a fully qualified name when there is only one class in the entire standard library named Path , and I don’t have my own class of this name?" - Remember that Java is for code reuse. When your code is used in another project, this project may have such a class or may use a third-party library that has and your code will be ambiguous.

+2
source

You need to use import in the second example because you are declaring a variable.

This has nothing to do with lambda expressions. If you used an anonymous class, you would have exactly the same.

0
source

I think the meaning that you are trying to illustrate can be simplified as follows:

This lambda requires import

Paths.get("path").forEach((Path filePath) -> {});

This lambda does not require import

Paths.get("path").forEach((filePath) -> {});

Since Path.forEach(...) accepts Consumer<? super Path> Consumer<? super Path> , I assume the latter case creates a new type "on the fly" ? super Path ? super Path , and therefore you do not need import, as this is a new type (for example, a generic type at runtime)

0
source

Source: https://habr.com/ru/post/1212054/


All Articles