2

I was looking for a way to get all the files ending with .txt in the current directory. I found the answer of how to do this here https://stackoverflow.com/a/5751357/3972558 and it works. Now I am reviewing my own code and I still do not quite understand how this works, and I am trying to learn from that.

    File workingDirectory = new File(System.getProperty("user.dir"));
    File[] files = workingDirectory.listFiles(new FilenameFilter() {
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".txt");
        }
    });

How is it possible that you declare a method within where you would usually find a parameter input? I probably ask my question in the wrong way because I do not understand why this syntax is correct.

In specific, how is this a correct input of listFiles():

new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.toLowerCase().endsWith(".txt");
            }
        }

Update: I now see that indeed you're implementing the accept method for the FileNameFilter interface. How is it possible though that you implement it after the keyword new.

http://docs.oracle.com/javase/7/docs/api/java/io/File.html http://docs.oracle.com/javase/7/docs/api/java/io/FileFilter.html

Community
  • 1
  • 1
Joop
  • 3,706
  • 34
  • 55

4 Answers4

2

Ok FilenameFilter is a abstract class, with the abstract method accept(). You have to implement this and all other stuff (e.g. comparing each filename), will done by FilenameFilter. You have to implement it after new because for creating a new Filter Java has to know in wich way you want FilenameFilter to work.

It's a basic idea of java to make some method abstract and you have to implement it on the way to say what you want to do in your special case. I hope it makes it a little bit more clear!

jBeenenga
  • 317
  • 2
  • 11
  • 1
    It does, thanks. I probably should read more about them first. – Joop Dec 12 '14 at 10:51
  • 1
    `FilenameFilter` is a `FunctionalInterface`, and is annotated as such. It is basically a interface with exactly one `abstract` method. More here: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html – Ian2thedv Dec 12 '14 at 10:52
1

You don't declare a method. It is a class there as a parameter. It is an abstract class and you provide an anonymous class implementation.

ACV
  • 9,964
  • 5
  • 76
  • 81
1

It's an anonymous class.

File::listFiles(FilenameFilter filter) take as parameter a FilenameFilter.
You can create your own FilenameFilter in a classic way:

public class MyFilter extends FilenameFilter {
    public boolean accept(File dir, String name) {
        return name.toLowerCase().endsWith(".txt");
    }
}

and then use it like this workingDirectory.listFiles(new MyFilter());.
But for convenience, we often use the anonymous class mechanism to avoid writing such a tiny class.

For example, here is a little snippet using anonymous class.

public class Duck {
    public String couak() {
        return "couak couak";
    }
}

public static void main(String[] args) {
     Duck englishDuck = new Duck();
     // In the next line, we create a Duck and override the couak() method
     Duck frenchDuck = new Duck() {
         @Override
         public String couak() {
             return "coin coin";
         }
     };
     System.out.println(englishDuck.couak());
     System.out.println(frenchDuck.couak());
}
NiziL
  • 5,068
  • 23
  • 33
1

I hope your problem to filter files within directory has been resolved, Your question is directly relevant that how this code is working. This is just one example of Anonymous Class. you read more about it over here. summary of this article is;

Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.

This is really handy when you want implementation of a class only once for example in you case if you had to use your filter in multiple places you would create a class which implements FilenameFilter like following;

public class TxtFileFilter implements FilenameFilter {

    @Override
    public boolean accept(File arg0, String arg1) {
        return arg1.toLowerCase().endsWith(".txt");
    }
}

and use it like following at different places

File[] files = workingDirectory.listFiles(new TxtFileFilter());

I hope this would help. Happy coding :)

Mubashar
  • 12,300
  • 11
  • 66
  • 95