java 8 lambda expression for FilenameFilter

2022-09-02 14:21:45

我正在浏览java 8中的lambda表达式

当我更改线程的代码时,它工作正常

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("run");
    }
}).start();

转换为 lambda 表达式

new Thread(
    () -> System.out.println("Hello from thread")
).start();

但我无法转换文件名过滤器表达式

File file = new File("/home/text/xyz.txt");
file.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        name.endsWith(".txt");
        return false;
    }
});

并未成功转换为此

file.list(new FilenameFilter () {
    (File a1, String a2) -> { 
        return false;
    }
});

它给出的错误就像在日食中一样

此行
处有多个标记 - 语法错误,插入“;”以完成语句
- 语法错误,插入“}”以完成块
- 语法错误,插入“AssignmentOperator 表达式”以完成赋值


答案 1

首先,你的格式很糟糕,整理出来!

现在,lambda 语法;转换匿名类:

final FilenameFilter filter = new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        return false;
    }
};

我们首先将匿名类替换为单个方法的等效 lambda:accept(File dir, String name)

final FilenameFilter filter = (File dir, String name) -> {
    return false;
};

但是我们可以做得更好,我们不需要定义类型 - 编译器可以解决这些:

final FilenameFilter filter = (dir, name) -> {
    return false;
};

而且我们还可以做得更好,因为该方法返回一个;如果我们有一个计算结果为 a 的语句,我们可以跳过 和 大括号:booleanbooleanreturn

final FilenameFilter filter = (dir, name) -> false;

这可以是任何语句,例如:

final FilenameFilter filter = (dir, name) -> !dir.isDirectory() && name.toLowerCase().endsWith(".txt");

但是,API非常古老,因此请勿使用它。使用 nio API。这自2011年Java 7以来一直存在,所以真的没有任何借口:File

final Path p = Paths.get("/", "home", "text", "xyz.txt");
final DirectoryStream.Filter<Path> f = path -> false;
try (final DirectoryStream<Path> stream = Files.newDirectoryStream(p, f)) {
    stream.forEach(System.out::println);
}

事实上,您的示例内置了一个特定的方法,该方法需要一个 GlobFiles

final Path p = Paths.get("/", "home", "text", "xyz.txt");
try (final DirectoryStream<Path> stream = Files.newDirectoryStream(p, "*.txt")) {
    stream.forEach(System.out::println);
}

或者,使用更现代的文件列表

final Path p = Paths.get("/", "home", "text", "xyz.txt");
final PathMatcher filter = p.getFileSystem().getPathMatcher("glob:*.txt");
try (final Stream<Path> stream = Files.list(p)) {
    stream.filter(filter::matches)
          .forEach(System.out::println);
}

下面是一个方法参考,因为该方法可用于实现函数接口,因为它采用 a 并返回 .filter::matchesPathMatcher.matchesPredicate<Path>Pathboolean


顺便说一句:

f.list(new FilenameFilter() {

    @Override
    public boolean accept(File dir, String name) {
        name.endsWith(".txt");
        return false;
    }
});

这是没有道理的...


答案 2

FileNameFilter是一个功能接口。您不需要显式实例化它。

    f.list((dir, name) -> name.endsWith(".txt"));

另请注意,这应该是一个目录,而不是示例中的文件。您的示例是一个文件,将返回指定的筛选器。ff1null


推荐