Java method refactoring: getting the file name or path I have been learning about refactoring and I have this method that I'm wondering if I should split into two for code cleanness. First, the method as one, next the method split in two:

Method not split:

public static ArrayList&lt;String&gt; getFilePathOrName(String pathOrName) {
    ArrayList&lt;String&gt; files = new ArrayList&lt;&gt;();
    File folder = new File("C:\\Users\\damar\\OneDrive\\Documenten\\FolderTest\\Folderretouren\\Niet verdeeld");
    File[] listOfFiles = folder.listFiles();

    if(pathOrName.equalsIgnoreCase("path")) {
        for (File file : listOfFiles) {
            if (file.isFile()) {
                files.add(file.toString());
            }
        }
    } else if(pathOrName.equalsIgnoreCase("name")) {
        for (File file : listOfFiles) {
            if (file.isFile()) {
                files.add(file.getName());
            }
        }
    }
    return files;
}


Method split:

public static ArrayList&lt;String&gt; getAllUndistributedFilesNames() {
    ArrayList&lt;String&gt; files = new ArrayList&lt;&gt;();
    File folder = new File("C:\\Users\\damar\\OneDrive\\Documenten\\FolderTest\\Folderretouren\\Niet verdeeld");
    File[] listOfFiles = folder.listFiles();

    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.getName());
        }
    }
    return files;
}

public static ArrayList&lt;String&gt; getAllUndistributedFilesPaths() {
    ArrayList&lt;String&gt; files = new ArrayList&lt;&gt;();
    File folder = new File("C:\\Users\\damar\\OneDrive\\Documenten\\FolderTest\\Folderretouren\\Niet verdeeld");
    File[] listOfFiles = folder.listFiles();

    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.toString());
        }
    }
    return files;
}


I feel like the method names when they are split is more intuitive. However, I'm not sure if that is enough justification to have this much duplicate code.
When we refactor the aim is to reduce code duplication. but you introduced even more duplication.

The way to go is to look out for code that is similar and make it the same.

When looking at your original method the duplication is in the if/else cascade. This means you should deal with that. The obvious differences are: 


the string literal used
the else before the second if
the method called at the object file


Lets convert that in thee steps:


the else is not needed for business reasons. It is introduced for performance optimization. You can safely remove this else and verify by measurement it that has really an impact. My guess is it does not. so lets let rid of it:

if(pathOrName.equalsIgnoreCase("path")) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.toString());
        }
    }
}
if(pathOrName.equalsIgnoreCase("name")) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.getName());
        }
    }
}

now you can extract the first literal string into a variable:

String requestedPathName = "path";
if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.toString());
        }
    }
}
if(pathOrName.equalsIgnoreCase("name")) {
  // ...


Then, after the first if block we can resuse this variable:

String requestedPathName = "path";
if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(file.toString());
        }
    }
}
requestedPathName = "name";
if(pathOrName.equalsIgnoreCase(requestedPathName)) {
  // ...

The last change requires to use an interface. This interface should declare a method that takes a file object as a parameter and returns a String object. One option is to define such interface yourself:

@FunctionalInterface
interface FileToStringConverter{
     String convert(File file);
}


Or we use the Function interface provides by the Java standard Lib. I choose the latter.

The principle is the same as with the string literal before:

replace the original code with the interface usage:

if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(new Function&lt;File,String&gt;(){ 
      @Override public String apply(File t){
           t.toString();
         }
      }.apply(file));
        }
    }
}


extract the interface implementation to a local variable:

// interface implemented as Lambda and method reference.
Function&lt;File,String&gt; converter = File::toString; // interface implemented as Lambda and method reference.
 if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(converter.apply(file)); 
        }
    }
}


repeat this in the other `if block:

String requestedPathName = "path";
Function&lt;File,String&gt; converter = File::toString;
  if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(converter.apply(file));
        }
    }
}
requestedPathName = "name";
converter = File::getName;
if(pathOrName.equalsIgnoreCase(requestedPathName)) {
    for (File file : listOfFiles) {
        if (file.isFile()) {
            files.add(converter.apply(file));
        }
    }
}



Now both if blocks look exactly the same. You can select one of them and apply your IDEs extract method automated refactoring feature:

public static ArrayList&lt;String&gt; getFilePathOrName(String pathOrName) {
    ArrayList&lt;String&gt; files = new ArrayList&lt;&gt;();
    File folder = new File("C:\\Users\\damar\\OneDrive\\Documenten\\FolderTest\\Folderretouren\\Niet verdeeld");
    File[] listOfFiles = folder.listFiles();

        String requestedPathName = "path";
        Function&lt;File,String&gt; converter = File::getName;
        // of cause you should choose a better name for the method!
        extracted(requestedPathName, pathOrName, converter, listOfFiles, files); 
        requestedPathName = "name";
        converter = File::getName;
        extracted(requestedPathName, pathOrName, converter, listOfFiles, files);

    return files;
}

private void extracted(
           String requestedPathName, 
           String pathOrName, 
           Function&lt;File,String&gt; converter,
           File[] listOfFiles, 
           List&lt;File&gt; files) { 
    if(pathOrName.equalsIgnoreCase(requestedPathName)) {
        for (File file : listOfFiles) {
            if (file.isFile()) {
                files.add(converter.apply(file));
            }
        }
    }
}


last step is inlineing the variables:

     extracted("path", pathOrName, File::toString, listOfFiles, files);
     extracted("name", pathOrName, File::getName, listOfFiles, files);


The complete result (with a better name for the extracted method) is:

public static ArrayList&lt;String&gt; getFilePathOrName(String pathOrName) {
    ArrayList&lt;String&gt; files = new ArrayList&lt;&gt;();
    File folder = new File("C:\\Users\\damar\\OneDrive\\Documenten\\FolderTest\\Folderretouren\\Niet verdeeld");
    File[] listOfFiles = folder.listFiles();

    addPathOrNameToList("path", pathOrName, File::toString, listOfFiles, files);
    addPathOrNameToList("name", pathOrName, File::getName, listOfFiles, files);       

    return files;
}

private void addPathOrNameToList(
           String requestedPathName, 
           String pathOrName, 
           Function&lt;File,String&gt; fileToStringConversion,
           File[] listOfFiles, 
           List&lt;File&gt; files) { 
    if(pathOrName.equalsIgnoreCase(requestedPathName)) {
        for (File file : listOfFiles) {
            if (file.isFile()) {
                files.add(fileToStringConversion.apply(file));
            }
        }
    }
}




We could turn the repeated method call into a loop if we would introduce another interface or an enum to encapsulate the differing data.