1. 简介

在 Java 引入 @FunctionalInterface 注解之前,就已经存在不少函数式接口(Functional Interface)。FilenameFilter 就是其中之一。

虽然它属于较早的一批接口,但在某些场景下依然实用。本文将带你快速了解它的作用和使用方式,并探讨它在现代 Java 开发中的定位。

2. FilenameFilter 接口详解

FilenameFilter 是一个典型的函数式接口 —— ✅ 只包含一个抽象方法,因此可以被用作 Lambda 表达式的目标类型。

其核心方法定义如下:

boolean accept(File dir, String name);

这个方法接收两个参数:

  • dir:当前遍历的目录(File 对象)
  • name:该目录下的文件或子目录名称(不包含路径)

返回 true 表示保留该文件名,false 则过滤掉。

⚠️ 注意:它只关心“名字”,不直接操作文件内容或属性。

3. 使用方式

FilenameFilter 主要用于筛选指定目录中满足条件的文件名。java.io.File 类提供了两个重载方法支持传入 FilenameFilter

  • String[] list(FilenameFilter filter)
  • File[] listFiles(FilenameFilter filter)

这两个方法会返回符合过滤规则的文件名数组或 File 对象数组。

示例:筛选 JSON 文件

下面这个测试用例展示了如何使用 FilenameFilter 找出目录下所有以 .json 结尾的文件:

@Test
public void whenFilteringFilesEndingWithJson_thenEqualExpectedFiles() {
    FilenameFilter filter = (dir, name) -> name.endsWith(".json");

    String[] expectedFiles = { "people.json", "students.json" };
    File directory = new File(getClass().getClassLoader()
      .getResource("testFolder")
      .getFile());
    String[] actualFiles = directory.list(filter);

    Assert.assertArrayEquals(expectedFiles, actualFiles);
}

✅ 要点总结:

  • 使用 Lambda 简化实现,代码更简洁
  • endsWith(".json") 是简单粗暴但有效的匹配方式
  • 测试资源路径通过 ClassLoader 获取,避免硬编码路径问题(踩坑提醒:Windows 和 Linux 路径分隔符差异)

3.1 FilenameFilter 与 BiPredicate 的关系

Java 8 新增了超过 40 个通用函数式接口,其中 BiPredicate<T, U> 特别值得关注:

boolean test(T t, U u);

对比 FilenameFilteraccept(File dir, String name) 方法,你会发现:

FilenameFilter 本质上就是 BiPredicate<File, String> 的特化版本!

也就是说:

FilenameFilter filter = (dir, name) -> name.endsWith(".json");

等价于:

BiPredicate<File, String> predicate = (dir, name) -> name.endsWith(".json");

但区别在于:

  • BiPredicate 不能直接用于 File.list() 方法(类型不匹配)
  • FilenameFilter 是专门为文件系统设计的,语义更清晰

所以虽然 BiPredicate 更通用,但在处理文件名过滤时,FilenameFilter 依然是最贴合场景的选择。

4. 总结

尽管现代 Java 提供了更强大的 PredicateBiPredicate 等泛型函数式接口,但 FilenameFilter 依然有它的存在价值:

  • ✅ 历史悠久,广泛存在于现有项目和 JDK API 中
  • ✅ 专为文件名过滤设计,语义明确,开箱即用
  • ✅ 结合 Lambda 使用,代码简洁直观

📌 因此,在合适的场景下(比如简单的目录扫描 + 文件扩展名过滤),完全可以直接使用 FilenameFilter,不必强行“现代化”。

所有示例代码均可在 GitHub 上获取:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-io-apis


原始标题:Quick Use of FilenameFilter | Baeldung