Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do Java Lambda Expressions Utilize "Hidden" or Local Package Imports?

Tags:

java

lambda

This question is about the apparent "hidden" or local imports of Java packages that lambda expressions seem to employ.

The following sample code compiles and runs fine (it just lists the files in the given 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 variable filePath is an instance of Path, whose implementation I think is contained in package java.nio.file.Path, although there is no import for that package.

Now, if I make a small modification, say by refactoring the call to System.out.println to its 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);
    }
}

I must now 'import' import java.nio.file.Path, otherwise I get a compiler error.

So my questions are:

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

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

The methods available to call on both filePath and passedFilePath are identical, leading me to believe they are both instances of java.nio.file.Path.

like image 369
mbmast Avatar asked Jan 27 '15 21:01

mbmast


1 Answers

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.

like image 134
Holger Avatar answered Sep 23 '22 22:09

Holger