Sem ter todos os requisitos de um caso concreto (ou seja, uma necessidade real em um sistema de verdade), podemos ficar debatendo eternamente sobre como melhorar.
Por exemplo, se eu faço new Classificador("/minhaPasta")
, então esta instância só vai ler os arquivos daquela pasta (não parece ter como mudar). Se a intenção era essa mesmo, ok. Senão, deveria ter um modo de alterar a pasta.
Se as categorias são fixas e vc só quer elas, e não precisa de todos os outros arquivos, então também não precisaria da lista contendo todos. Outro detalhe é que, da forma atual, vc primeiro cria a lista com todos, e depois filtra ela duas vezes, uma para cada categoria. Ou seja, a lista é percorrida duas vezes. Mas e se tivesse mais critérios? Aí teria que percorrer várias vezes, o que não é uma solução muito escalável.
Enfim, daria para filtrar tudo de uma vez, e sem precisar criar a lista com todos (que não parece ser necessária):
public class Classificador {
private final List<Path> arquivosDaCategoria1 = new ArrayList<>();
private final List<Path> arquivosDaCategoria2 = new ArrayList<>();
public Classificador(String pathDaPasta) {
try (Stream<Path> paths = Files.walk(Paths.get(pathDaPasta))) {
paths.forEach(path -> { // para cada arquivo na pasta
String nome = path.getFileName().toString();
if (nome.startsWith("exemplo")) { // se começa com "exemplo", adiciona na categoria 1
arquivosDaCategoria1.add(path);
}
if (nome.endsWith(".pdf")) { // se termina com ".pdf.", adiciona na categoria 2
arquivosDaCategoria2.add(path);
}
});
} catch (IOException e) {
// erro, mostra alguma mensagem (ou relança a exceção, não deixando criar a instância)
}
}
public List<Path> getArquivosDaCategoria1() {
return arquivosDaCategoria1;
}
public List<Path> getArquivosDaCategoria2() {
return arquivosDaCategoria2;
}
}
Também arrumei a verificação, pois se eu fizer path.startsWith
, ele não se comporta da forma esperada. Por exemplo, se eu verificar a pasta abc
, o path do arquivo será abc/exemplo
, ou seja, nunca começará com “exemplo”. Por isso precisa fazer o ajuste (saiba mais aqui).
Indo um pouco além, a classe seria mais útil e flexível se pudesse receber os critérios no construtor. Algo assim:
public class Classificador {
// mapeia cada critério para sua respectiva lista
private Map<String, List<Path>> categorias = new HashMap<>();
public Classificador(String pathDaPasta, Map<String, Predicate<Path>> criterios) {
try (Stream<Path> paths = Files.walk(Paths.get(pathDaPasta))) {
paths.forEach(path -> { // para cada arquivo
// verifica se ele se encaixa em cada um dos critérios
// em caso afirmativo, adiciona na respectiva lista
for (Map.Entry<String, Predicate<Path>> e : criterios.entrySet()) {
if (e.getValue().test(path)) {
categorias.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(path);
}
}
});
} catch (IOException e) {
// erro, mostra alguma mensagem (ou relança a exceção, não deixando criar a instância)
}
}
public List<Path> getArquivos(String categoria) {
return categorias.getOrDefault(categoria, Collections.emptyList());
}
}
Um exemplo de uso:
Map<String, Predicate<Path>> criterios = Map.of(
"categoria 1", path -> path.getFileName().toString().startsWith("exemplo"),
"categoria 2", path -> path.getFileName().toString().endsWith(".pdf"),
"categoria 3", path -> path.toFile().length() > 100 // arquivo maior que 100 bytes
// adicione quantas categorias quiser
);
Classificador c = new Classificador("/tmp/hugo/", criterios);
for (String categoria : criterios.keySet()) {
System.out.println(categoria + ": " + c.getArquivos(categoria));
}
E como eu já disse, sem saber os requisitos (se precisa mesmo ter vários critérios configuráveis, etc), podemos debater infinitamente sobre formas de melhorar…