0

Can you override a method in this way?

public class test {

    public static void main(String[] args) throws IOException {        
        File dir = new File("M:\\Java\\Test") {
            @Override
            public String[] list() { 
                String[] listA = super.list();                
                for (String s : listA) {
                    s = "test" + s;
                }                
                return listA;
            }
        };
        String[] listB = dir.list();
        for (String s : listB) {
            System.out.println(s);
        }
    }
}

I expected:

test1.txt
test10.txt
test2.txt
test3.txt
test4.txt
test5.txt
test6.txt
test7.txt
test8.txt
test9.txt

I received:

1.txt
10.txt
2.txt
3.txt
4.txt
5.txt
6.txt
7.txt
8.txt
9.txt

I can't ask a new question and it concerns the same code so I will ask here. Is a compiler error caused by nesting method overrides?

public class test {

    public static void main(String[] args) throws IOException {
        File dir = new File("M:\\Java\\Test") {
            @Override
            public String[] list() {
                String[] listA = super.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File file, String string) {
                        return string.contains(".txt");
                    }
                });
                for (int i = 0; i < listA.length; i++) {
                    listA[i] = "test" + listA[i];
                }                                
                return listA;
            }
        };
        String[] listB = dir.list();
        for (String s : listB) {
            System.out.println(s);
        }
    }
}

I recived:

    Exception in thread "main" java.lang.StackOverflowError  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155) 

It looks like some infinite loop. The problem arose after adding FilenameFilter to the list() function. Is this the result of nested @Override?

kAEm
  • 27
  • 3

5 Answers5

2

You are returning the same list. Replace your for loop with this:

        for(int i=0;i<listA.length;i++)
        {
            listA[i] = "test" + listA[i];
        }
Shubhendu Pramanik
  • 2,711
  • 2
  • 13
  • 23
2

The issue is with this line:

s = "test" + s;

All that does is update the s variable. It has no effect whatsoever on the string in the list.

Instead, build a new array with the updated names, and return that.

@Override
public String[] list() { 
    String[] listA = super.list();                
    String[] listB = new String[listA.length]; // ***
    int n = 0;                                 // ***
    for (String s : listA) {
        listB[n++] = "test" + s;               // ***
    }                
    return listB;                              // ***
}

Side note: File#list can return null:

Returns:

An array of strings naming the files and directories in the directory denoted by this abstract pathname. The array will be empty if the directory is empty. Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.

(my emphasis)

...so you'll want to handle that possibility:

@Override
public String[] list() { 
    String[] listA = super.list();                
    if (listA == null) {                       // ***
        return null;                           // ***
    }                                          // ***
    String[] listB = new String[listA.length];
    int n = 0;
    for (String s : listA) {
        listB[n++] = "test" + s;
    }                
    return listB;
}
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    I'm not sure why I didn't update `listA` like [the answer](https://stackoverflow.com/a/57805224/157247) I now see Shubhendu posted. No good reason, really; that would probably be better since the `File` class is handing over the array for use by the caller, it won't be keeping it for its own purposes... – T.J. Crowder Sep 05 '19 at 12:16
0

Here:

String[] listA = super.list();                
for (String s : listA) {
   s = "test" + s;
}                

You create a new string object, and assign that to a reference that formerly pointed to a member of your array.

Then:

 return listA;

you return that array.

Your code does not change the content of the array. You iterate the array, create a new string for each entry. Then you throw that new string away, to then return the original, unmodified array.

You could a one liner like:

return Arrays.stream(super.list()).map(s -> s = "test" + s).toArray(String[]::new);

Besides that, I would be really careful about using polymorphism like that. The contract of the File says: this method returns the "child file" names. The contract doesn't say: it returns manipulated file names. So, for real, production code usage, I would rather create a helper/utilities class that implements its "own" contract, that says: "give me a list of files, and I prepend them in a meaningful way with a prefix".

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • String[] listB = dir.list(); for (String s : listB) { s = "test" + s; System.out.println(s); So why does this code work? – kAEm Sep 05 '19 at 12:29
  • Excuse me. I am a new forum user. I don't know the convention. I will remember about this. – kAEm Sep 05 '19 at 12:45
  • @kAEm It wasn't necessary to change the accept though. Anyway: I am glad that you got answers to your question quickly! – GhostCat Sep 05 '19 at 12:47
0

This

String[] listA = super.list();                
for (String s : listA) {
  s = "test" + s;
}                
return listA;

does not do what you expect. Try

for (int i = 0; i < listA.length; i++) {
  listA[i] = "test" + listA[i];
}
0

String is an immutable class, so s = "test" + s; has no affect here. You should use something like this:

File dir = new File(".") {
  @Override
  public String[] list() {
    String[] listA = super.list();
    if (listA != null) {
      for (int i = 0; i < listA.length; i++) {
        listA[i] = "test" + listA[i];
      }
    }
    return listA;
  }
};
String[] listB = dir.list();
if (listB != null) {
  for (String s : listB) {
    System.out.println(s);
  }
}
Oleksandr Lykhonosov
  • 1,138
  • 12
  • 25