First of all, you should do benchmarking to figure out where is the exact bottleneck. How do I write a correct micro-benchmark in Java? should be a good start.
Now, an idea, which might help.
- Get all files and directories in a single array. Like this you are getting file and folders with a single operation, instead of two. Accessing file and folders on the disk is not exactly fast operation, so you would want to reduce those. Also if you take a look at the implementation of
listFiles(FileFilter)
, it iterates everything in the folder to find matches, so that's 1 less iteration of all elements.
File[] directoriesAndFiles = folder.listFiles();
- As mentioned in other answer
isFile
, isDirectory
are slow, calling them more than once is not desirable. You can define your wrapper class (record in this case) to cache the results.
public record FileWrapper(File file, String name, boolean isDirectory, boolean isFile) {
}
- Write composite comparator for the sort. Judging by code you want directories first.
public class FileTypeComparator implements Comparator<FileWrapper> {
@Override
public int compare(FileWrapper first, FileWrapper second) {
if (first.isDirectory() && second.isFile()) {
return -1;
}
if (first.isFile() && second.isDirectory()) {
return 1;
}
return 0;
}
}
Combine it with your by name comparator:
Comparator<FileWrapper> compositeComparator = new FileTypeComparator()
.thenComparing(FileWrapper::name, String.CASE_INSENSITIVE_ORDER);
Then build the result array with a stream
File[] result = Arrays.stream(directoriesAndFiles)
.map(file -> new FileWrapper(file, file.getName(), file.isDirectory(), file.isFile())) //map to wrapper class to cache result of expensive methods
.filter(fw -> fw.isFile() || fw.isDirectory()) //filter out not needed elements
.sorted(compositeComparator) //sort with composite comparator
.map(FileWrapper::file) //extract files from the wrapper
.toArray(File[]::new); //collect in array
Additionally, to avoid building the initial array you can use Files.list() to get lazily populated stream.
try (Stream<Path> stream = Files.list(Path.of("initial directory"))) {
File[] result = stream
.map(Path::toFile)
.map(file -> new FileWrapper(file, file.getName(), file.isDirectory(), file.isFile()))
.filter(fw -> fw.isFile() || fw.isDirectory())
.sorted(compositeComparator)
.map(FileWrapper::file)
.toArray(File[]::new);
} catch (IOException exc) {
//handle
}