Как мне правильно настроить сортировку коллекции в Java
Есть код который ищет в папках файлы нужного размера. Все работало нормально, но по условиям задания нужно было добавить многопоточность, ее я добавил, разделив работу тем, что один поток перебирает папку и подпапки, а второй пишет в консоль соответствующие условию файлы. Но когда он выводил сразу в консоль файлы переставала работать сортировка(нужно по убыванию размера), использовал метод - fileList.sort(Comparator.comparingLong(File::length).reversed());
Что бы он снова заработал мне посоветовали выводить ни сразу в консоль файлы, а собирать их в коллекцию , потом сортировать и печатать, я добавил сбор в коллекцию в этом методе "processFile()", но вероятно как-то криво, потому, что файлы нужные выводиться так же в консоль, но сортировка не работает, подскажите, кто знает, как сортировку настроить в моем случае.
import java.io.File;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
public class Main{
static Scanner in = new Scanner(System.in);
static File directory = new File(in.next());
public static final double MIN_LENGTH = in.nextDouble() * 1048576;
static int numOfThreads = 4; // количество потоков
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool(numOfThreads);
FileTask task = new FileTask(directory);
pool.invoke(task);
}
public static class FileTask extends RecursiveAction {
private final File file;
public FileTask(File file) {
this.file = file;
}
@Override
protected void compute() {
if (file.isDirectory()) {
processDir();
} else if (file.isFile() && file.length() > MIN_LENGTH) {
processFile();
}
}
private void processFile() {
ArrayList<File> fileList = new ArrayList<>();
fileList.add(file);
fileList.sort(Comparator.<File>comparingLong(File::length).reversed());
for(File file: fileList) {
if (file.length() >= 1073741824) {
DecimalFormat df = new DecimalFormat("#.#");
double Gb = (double) file.length() / 1073741824;
System.out.printf("%s Gb %s%n", df.format(Gb), file);
} else if (file.length() >= 1048576) {
System.out.printf("%s Mb %s%n", file.length() / 1048576, file);
} else if (file.length() >= 1024) {
System.out.printf("%s Kb %s%n", file.length() / 1024, file);
} else if (file.length() < 1024) {
System.out.printf("%s B %s%n", file.length(), file);
} else {
System.out.printf("%s Tb %s%n", file.length() / (1073741824 * 1024), file);
}
}
}
private void processDir() {
ArrayList<FileTask> tasks = new ArrayList<>();
File[] subFiles = file.listFiles();
for (File sub: subFiles) {
tasks.add(new FileTask(sub));
}
ForkJoinTask.invokeAll(tasks);
}
}
}
Ответы (1 шт):
Вам совершенно правильно посоветовали собирать их(файлы) в коллекцию , потом сортировать и печатать, поэтому следовало для начала вынести печать из метода processFile на уровень основного класса, и также использовать RecursiveTask<List<File>>, который возвращал бы список файлов:
public static class FileTask extends RecursiveTask<List<File>> {
private final File file;
public FileTask(File file) {
this.file = file;
}
@Override
protected List<File> compute() {
if (file.isDirectory()) {
return ForkJoinTask.invokeAll(processDir())
.stream()
.map(ForkJoinTask::join)
.flatMap(List::stream)
.collect(Collectors.toList());
} else if (file.isFile() && file.length() > minLength) {
return processFile();
}
return Collections.emptyList();
}
private List<File> processFile() {
return Collections.singletonList(file);
}
private Collection<FileTask> processDir() {
return Arrays.stream(file.listFiles())
.map(FileTask::new)
.collect(Collectors.toList());
}
}
Тогда основной функционал может выглядеть так:
public static double minLength = 1024;
public static final int NUM_OF_THREADS = 4; // количество потоков
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool(NUM_OF_THREADS);
Scanner in = new Scanner(System.in);
System.out.print("Введите путь: ");
File directory = new File(in.nextLine());
System.out.print("Введите минимальный размер файла в килобайтах: ");
minLength *= in.nextInt();
FileTask task = new FileTask(directory);
List<File> result = pool.invoke(task);
result.sort(Comparator.comparingLong(File::length).reversed());
result.forEach(Main::processFile);
}
private static void processFile(File file) {
if (file.length() >= 1073741824) {
DecimalFormat df = new DecimalFormat("#.#");
double Gb = (double) file.length() / 1073741824;
System.out.printf("%s Gb %s%n", df.format(Gb), file);
} else if (file.length() >= 1048576) {
System.out.printf("%s Mb %s%n", file.length() / 1048576, file);
} else if (file.length() >= 1024) {
System.out.printf("%s Kb %s%n", file.length() / 1024, file);
} else if (file.length() < 1024) {
System.out.printf("%s B %s%n", file.length(), file);
} else {
System.out.printf("%s Tb %s%n", file.length() / (1073741824 * 1024), file);
}
}