将Java流与组合集合一起使用

时间:2016-08-18 14:56:17

标签: java java-8 java-stream

我希望使用Java流来解决这类问题:

我有一个Library对象列表。

Library类包含一个Sections Map。 Sections包含BookShelf对象的List。 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;
    }
}

我想知道的是所有拥有该书的图书馆对象叫做&#34; Java 8&#34;。我认为这是一个可以使用流来回答的查询,但是,编写各种流调用我得到了Book对象的集合,而不是根库对象。

流是否适合使用嵌入对象和集合?我怎么做到这一点?

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

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);
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:0)

流是否合适可能是品味和可读性偏好的问题。在我看来,流代码和lambdas不是最易读的代码,但也许是你学会做的事情。在任何情况下,基本方法是根据是否存在标题为“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());
}

答案 1 :(得分:0)

使用约翰莫里斯的解决方案进行调整以支持地图解决问题:

/*
 * 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);
}