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.