Java 使用lambda的嵌套过滤器

Java 使用lambda的嵌套过滤器,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我正在尝试编写一个多级过滤器。我有文件夹和文件 public class Folder { String name; List<Folder> folders; List<File> files; ... } public class File { String name; String type; ... } 公共类文件夹{ 字符串名; 列出文件夹; 列出文件; ... } 公共类文件{ 字符串名; 字符串类型; ... } 我需要一个

我正在尝试编写一个多级过滤器。我有文件夹和文件

public class Folder {
  String name;
  List<Folder> folders;
  List<File> files;
  ...
}

public class File {
  String name;
  String type;
  ...
}
公共类文件夹{
字符串名;
列出文件夹;
列出文件;
...
}
公共类文件{
字符串名;
字符串类型;
...
}
我需要一个过滤器来查找某些属性,例如名称,可以是文件夹/文件名。我写了一段只适用于一个级别的代码,但我不知道如何通过寻找两个级别的循环来实现这一点

最终结果将是文件夹列表:名称与“名称筛选器”匹配的文件夹或文件名与筛选器匹配的文件夹

List<Folder> result = folders.stream()
  .filter(folder -> folder.getFiles().stream().anyMatch(file -> file.getName().contains(filter)))
  .collect(Collectors.toList());
List result=folders.stream()
.filter(文件夹->文件夹.getFiles().stream().anyMatch(文件->文件.getName().contains(过滤器)))
.collect(Collectors.toList());

我认为最好在Folder类中添加一个helper方法,该方法将嵌套文件夹以递归方式展平到流中:

class Folder {
    String name;
    List<Folder> folders;
    List<File> files;

    Stream<Folder> flatten() {
        return Stream.concat(Stream.of(this), folders.stream().flatMap(Folder::flatten));
    }
}

一个正在运行的测试,它通过文件夹中的文件名进行过滤(没有任何帮助器方法)

您的方法中最重要的部分就是@Ernest所指的flatMap旁边的区别,它将所有文件元素展平到一个列表中

private static final String FILE_NAME_FILTER = "1";
private static final String HOME_FOLDER_FILTER = "home";
private static final String VAR_FOLDER_FILTER = "var";
private static final String BIN_FOLDER_FILTER = "bin";

@Test
public void test() {
    File f1 = new File("1", "txt");
    File f2 = new File("1", "json");
    File f3 = new File("1", "yml");
    File f4 = new File("4", "doc");

    Folder folder1 = new Folder(HOME_FOLDER_FILTER, asList(f1, f2));
    Folder folder2 = new Folder(VAR_FOLDER_FILTER, asList(f2, f3));
    Folder folder3 = new Folder(BIN_FOLDER_FILTER, asList(f3, f4));
    List<Folder> folders = asList(folder1, folder2, folder3);

    List<File> files = folders.stream()
            .filter(folder -> folder.getName().equals(HOME_FOLDER_FILTER))
            .map(Folder::getFiles) // no helper method
            .flatMap(List::stream)
            .filter(file -> file.getName().equals(FILE_NAME_FILTER))
            .collect(Collectors.toList());
    Assert.assertEquals(2, files.size());
}
私有静态最终字符串文件\u NAME\u FILTER=“1”;
私有静态最终字符串HOME\u FOLDER\u FILTER=“HOME”;
私有静态最终字符串VAR\u FOLDER\u FILTER=“VAR”;
私有静态最终字符串BIN\u FOLDER\u FILTER=“BIN”;
@试验
公开无效测试(){
文件f1=新文件(“1”、“txt”);
文件f2=新文件(“1”、“json”);
文件f3=新文件(“1”,“yml”);
文件f4=新文件(“4”,“文件”);
Folder folder1=新文件夹(主文件夹过滤器,asList(f1,f2));
Folder folder2=新文件夹(变量文件夹过滤器,asList(f2,f3));
Folder folder3=新文件夹(BIN_Folder_过滤器,asList(f3,f4));
列表文件夹=asList(folder1、folder2、folder3);
列表文件=文件夹.stream()
.filter(folder->folder.getName().equals(HOME\u folder\u filter))
.map(Folder::getFiles)//无帮助程序方法
.flatMap(列表::流)
.filter(文件->文件.getName().equals(文件名\u过滤器))
.collect(Collectors.toList());
Assert.assertEquals(2,files.size());
}
与@Oleksandr的建议大致相同


编辑:我发现我忽略了一个事实,一个文件夹可以包含一个文件夹。我应该删除这个答案吗?

使用递归的方法可能是一个更好的主意
private static final String FILE_NAME_FILTER = "1";
private static final String HOME_FOLDER_FILTER = "home";
private static final String VAR_FOLDER_FILTER = "var";
private static final String BIN_FOLDER_FILTER = "bin";

@Test
public void test() {
    File f1 = new File("1", "txt");
    File f2 = new File("1", "json");
    File f3 = new File("1", "yml");
    File f4 = new File("4", "doc");

    Folder folder1 = new Folder(HOME_FOLDER_FILTER, asList(f1, f2));
    Folder folder2 = new Folder(VAR_FOLDER_FILTER, asList(f2, f3));
    Folder folder3 = new Folder(BIN_FOLDER_FILTER, asList(f3, f4));
    List<Folder> folders = asList(folder1, folder2, folder3);

    List<File> files = folders.stream()
            .filter(folder -> folder.getName().equals(HOME_FOLDER_FILTER))
            .map(Folder::getFiles) // no helper method
            .flatMap(List::stream)
            .filter(file -> file.getName().equals(FILE_NAME_FILTER))
            .collect(Collectors.toList());
    Assert.assertEquals(2, files.size());
}