假设您有几百个内存中对象的集合,并且您需要查询此List以返回与某些SQL或条件(如查询)匹配的对象.例如,您可能拥有一个汽车列表对象,并且您想要返回在20世纪60年代制造的所有汽车,车牌以AZ开头,按车型名称排序.
我知道JoSQL,有没有人使用过这个,或者有其他/本土解决方案的经验?
过滤是实现此目的的一种方式,如其他答案中所述.
但是过滤不可扩展.从表面上看,时间复杂度似乎是O(n)(即,如果集合中的对象数量增长,则已经不可扩展),但实际上是因为需要根据查询,时间对每个对象应用一个或多个测试复杂度更准确的是O(nt),其中t是应用于每个对象的测试数.
因此,随着将额外对象添加到集合中和/或随着查询中的测试数量的增加,性能将降低.
还有另一种方法可以使用索引和集合理论.
一种方法是在存储在集合中的对象中的字段上构建索引,然后在查询中对其进行测试.
假设您有一组Car
对象,并且每个Car
对象都有一个字段color
.假设您的查询等同于" SELECT * FROM cars WHERE Car.color = 'blue'
".您可以构建索引Car.color
,基本上如下所示:
'blue' -> {Car{name=blue_car_1, color='blue'}, Car{name=blue_car_2, color='blue'}} 'red' -> {Car{name=red_car_1, color='red'}, Car{name=red_car_2, color='red'}}
然后给出查询WHERE Car.color = 'blue'
,可以在O(1)时间复杂度中检索该组蓝色汽车.如果您的查询中还有其他测试,则可以测试该候选集中的每辆汽车,以检查它是否与查询中的其余测试相匹配.由于候选集可能明显小于整个集合,因此时间复杂度小于 O(n)(在工程意义上,请参见下面的评论).将其他对象添加到集合时,性能不会降低太多.但这仍然不完美,请继续阅读.
另一种方法是我将其称为常设查询索引.为了解释:使用传统的迭代和过滤,迭代集合并测试每个对象以查看它是否与查询匹配.因此,过滤就像在集合上运行查询一样.一个常设查询索引将是另一种方式,其中集合反而在查询上运行,但对于集合中的每个对象只运行一次,即使可以多次查询该集合.
一个站在查询索引会像某种注册查询智能集合,使得当对象被加入,并移除了,那么这个集合将自动检测每个对象对所有已注册与它的地位查询.如果对象与常设查询匹配,则该集合可以向/从专用于存储与该查询匹配的对象的集合添加/移除它.随后,可以以O(1)时间复杂度检索与任何已注册查询匹配的对象.
以上信息来自CQEngine(Collection Query Engine).这基本上是一个NoSQL查询引擎,用于使用类似SQL的查询从Java集合中检索对象,而无需迭代集合.它围绕上面的想法,再加上一些.免责声明:我是作者.它是开源的,在maven中心.如果您觉得它有用,请upvote这个答案!
我在生产应用程序中使用了Apache Commons JXPath.它允许您将XPath表达式应用于Java中的对象图.
是的,我知道这是一个老帖子,但技术每天都会出现,答案会随着时间的推移而改变.
我认为使用LambdaJ解决它是一个很好的问题.您可以在此处找到它:http: //code.google.com/p/lambdaj/
这里有一个例子:
寻找活跃的客户//(可转换的版本)
ListactiveCustomers = new ArrayList (); for (Customer customer : customers) { if (customer.isActive()) { activeCusomers.add(customer); } }
LambdaJ版本
ListactiveCustomers = select(customers, having(on(Customer.class).isActive()));
当然,拥有这种美感会影响性能(有点......平均2次),但是你能找到更易读的代码吗?
它有许多功能,另一个例子可能是排序:
排序迭代
ListsortedByAgePersons = new ArrayList (persons); Collections.sort(sortedByAgePersons, new Comparator () { public int compare(Person p1, Person p2) { return Integer.valueOf(p1.getAge()).compareTo(p2.getAge()); } });
用lambda排序
ListsortedByAgePersons = sort(persons, on(Person.class).getAge());