使用具有组合集合的Java流

我正在寻找使用Java流来解决这类问题:

我有一个库对象列表。

库类包含剖面图。 部分包含BookShelf对象的列表。 BookShelf包含一个Book对象的Map。

class Library {
    Map<String, Section> sections = new HashMap<String, Section>();
    String name;
    public String toString() {
        return name;
    }
}

class Section {
    List<BookShelf> bookShelves = new ArrayList<BookShelf>();
}

class BookShelf {
    Map<String, Book> books = new HashMap<String, Book>();
}

class Book {
    String name;
    Book(String name) {
       this.name = name;
    }
}

我想知道的是所有具有名为“Java 8”的书的库对象。 我认为这是一个可以使用流来回答的查询,然而,编码各种流调用我得到一个Book对象集合,而不是根Library对象。

流适合使用嵌入对象和集合吗? 我将如何实现这一目标?

下面是一个简单的代码,它使用传统的循环来找到答案:

List<Library> libraries = new ArrayList<Library>();

Library lib = new Library();
lib.name = "Houston Central";
libraries.add(lib);

Section section = new Section();
lib.sections.put("Reference", section);

BookShelf shelf = new BookShelf();
section.bookShelves.add(shelf);

Book book = new Book("Java 8");
shelf.books.put("Java 8", book);

book = new Book("Java 7");
shelf.books.put("Java 7", book);


/*
 * Search for a Library containing a specific book
 * using traditional loops.
 */
for(Library library : libraries) {
    for (Section sec : library.sections.values()) {
        for (BookShelf bookShelf : sec.bookShelves) {
            for (Book b : bookShelf.books.values()) {
                if (b.name.equals("Java 8")) {
                    System.out.println("Book is contained in Library " + library);
                }
            }
        }
    }
}

流是否合适可能是品味和可读性偏好的问题。 在我看来,流代码和lambda表达式并不能提供最易读的代码,但也许是你学习的东西。 在任何情况下,基本方法是根据是否存在标题为“Java 8”的书籍过滤库流,并将满足过滤谓词的库作为集合返回。 过滤本身要求将每个库变成书籍流,这需要两个平面映射操作。 然后,我使用anyMatch匹配书名并终止给定库的流。 你可以并行化我所期望的过程,但是我并没有在并行数据流上做很多事情。

下面提供的示例将搜索过程外化。 更合适的面向对象的方法将包括Section和BookShelf类中的图书搜索功能,这将大大提高可读性。

请记住,您正在顺序搜索一本书,顺序搜索速度很慢。 顺序搜索是O(n),而HashMap索引搜索是O(1)。 我会在BookShelf类中包含一个索引。 我提供了一个下面的顺序搜索算法的示例(未测试)。

public Collection<Library> hasBook(Collection<Library> libraries, String title) {
    return libraries.stream()
        .filter(x->x.sections()
                .stream()
                .flatMap(y->y.bookShelves()
                        .stream()
                        .flatMap(z->z.books().stream()))
                .anyMatch(b->b.title().equals(title)))
        .collect(Collectors.toList());
}

使用John Morris的解决方案来调整地图可以解决问题:

/*
 * Using Streams
 */
public static Collection<Library> hasBook(Collection<Library> libraries, String title) {
    return libraries.stream()
        .filter(x->x.sections.values()
                .stream()
                .flatMap(y->y.bookShelves
                        .stream()
                        .flatMap(z->z.books.values().stream()))
                .anyMatch(b->b.name.equals(title)))
        .collect(Collectors.toList());
}

调用代码:

/*
 * Search using streams
 */
Collection<Library> libs = hasBook(libraries, "Java 8");
for (Library l : libs) {
    System.out.println("Book is contained in Library (via streams) " + l);
}
链接地址: http://www.djcxy.com/p/16345.html

上一篇: Using Java streams with composed collections

下一篇: ConcurrentHashmap in JDK8 code explanation