1. Introduction

Java has had functional interfaces before the addition of the informative annotation, @FunctionalInterface. FilenameFilter is one such interface.

We’ll be taking a brief look at its usage and understand where it fits in the world of Java today.

2. FilenameFilter

Since this is a functional interface – we have to have exactly one abstract method, and FilenameFilter follows this definition:

boolean accept(File dir, String name);

3. Usage

We use FilenameFilter almost exclusively to list all files — that satisfy the specified filter — inside a directory.

The overloaded list(..) and listFiles(..) methods in java.io.File take an instance of FilenameFilter and return an array of all files that satisfy the filter.

The following test case filters all the json files in a directory:

@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);
}

3.1. FileFilter as BiPredicate

Oracle added more than 40 functional interfaces in Java 8, and unlike legacy interfaces, these are generic. That meant that we could use them for any reference type.

BiPredicate<T, U> was one such interface. Its’ single abstract method has this definition:

boolean test(T t, U u);

What this means is that FilenameFilter is just a special case of BiPredicate where T is File and U is String.

4. Conclusion

Even though we now have generic Predicate and BiPredicate functional interfaces, we’ll continue to see occurrences of FilenameFilter simply because it has been in use in existing Java libraries.

Also, it serves its single purpose well, so there’s no reason to not use it when applicable.

As always, all the examples are available over on GitHub.