Java非SQL场景下为List中Book属性建索引实现高效查询
解决方案
针对你的需求,完全可以通过自定义轻量容器或借助现有工具类实现高效的内存索引查询,以下是具体方案:
1. 自定义带链式查询的索引容器
你可以手动实现一个维护预定义索引的容器类,在添加书籍时同步更新所有索引,查询时直接通过索引获取集合并支持链式组合:
import java.util.*; public class BookStore { private final List<Book> allBooks = new ArrayList<>(); private final Map<String, Set<Book>> yearIndex = new HashMap<>(); private final Map<String, Set<Book>> authorIndex = new HashMap<>(); // 添加书籍时同步更新索引 public void addBook(Book book) { allBooks.add(book); yearIndex.computeIfAbsent(book.getYear(), k -> new HashSet<>()).add(book); authorIndex.computeIfAbsent(book.getAuthor(), k -> new HashSet<>()).add(book); } // 按年份查询,返回支持链式操作的中间对象 public QueryResult getYear(String year) { Set<Book> books = yearIndex.getOrDefault(year, Collections.emptySet()); return new QueryResult(new HashSet<>(books)); } // 按作者查询,返回支持链式操作的中间对象 public QueryResult getAuthor(String author) { Set<Book> books = authorIndex.getOrDefault(author, Collections.emptySet()); return new QueryResult(new HashSet<>(books)); } // 内部类实现链式组合查询 public class QueryResult { private final Set<Book> currentBooks; private QueryResult(Set<Book> books) { this.currentBooks = books; } public QueryResult andAuthor(String author) { currentBooks.retainAll(authorIndex.getOrDefault(author, Collections.emptySet())); return this; } public QueryResult andYear(String year) { currentBooks.retainAll(yearIndex.getOrDefault(year, Collections.emptySet())); return this; } // 获取最终查询结果 public List<Book> getResult() { return new ArrayList<>(currentBooks); } } }
使用示例完全匹配你的需求:
BookStore store = new BookStore(); store.addBook(new Book("Java编程思想", "2022", "Foo")); store.addBook(new Book("Effective Java", "2022", "X")); // 查询2022年的书籍 List<Book> year2022Books = store.getYear("2022").getResult(); // 查询作者为X的书籍 List<Book> authorXBooks = store.getAuthor("X").getResult(); // 查询2022年且作者为X的书籍 List<Book> filteredBooks = store.getYear("2022").andAuthor("X").getResult();
这种方式的查询复杂度取决于集合交集的规模,远低于O(n),完全满足高效查询要求。
2. 用Guava Multimap简化实现
如果不想手写太多代码,可以借助Guava的Multimap快速构建索引,结合集合交集操作实现组合查询:
import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Set; public class BookStore { private final Multimap<String, Book> yearToBooks = HashMultimap.create(); private final Multimap<String, Book> authorToBooks = HashMultimap.create(); public void addBook(Book book) { yearToBooks.put(book.getYear(), book); authorToBooks.put(book.getAuthor(), book); } public Collection<Book> getYear(String year) { return yearToBooks.get(year); } public Collection<Book> getAuthor(String author) { return authorToBooks.get(author); } public Set<Book> getYearAndAuthor(String year, String author) { Set<Book> yearBooks = Sets.newHashSet(yearToBooks.get(year)); Set<Book> authorBooks = Sets.newHashSet(authorToBooks.get(author)); return Sets.intersection(yearBooks, authorBooks); } }
这种方式省去了自定义链式查询的代码,组合查询直接通过Sets.intersection实现,效率同样高效。
关于类似list.addIndexOn(Book::title)的API
Java标准库中没有直接提供这类API,部分第三方ORM或内存数据框架(如EclipseLink内存模式)有类似功能,但对于你的轻量需求来说,自定义容器或使用Guava已经足够简洁,无需引入复杂框架。
内容的提问来源于stack exchange,提问作者user6412004
相关产品推荐
相关产品推荐

