如何在Java中查询对象集合(Criteria / SQL-like)?

如何在Java中查询对象集合(Criteria / SQL-like)?

How do you query object collections in Java (Criteria/SQL-like)?

假设您有几百个内存中对象的集合,并且您需要查询此List以返回与某些SQL或条件(如查询)匹配的对象。 例如,您可能拥有一个汽车列表对象,并且您希望返回20世纪60年代制造的所有汽车,其车牌以AZ开头,按车型名称排序。

我知道JoSQL,有没有人使用过这个,或者有其他/本土解决方案的经验?


过滤是实现此目的的一种方式,如其他答案中所述。

但是过滤不可扩展。从表面上看,时间复杂度似乎是O(n)(即,如果集合中的对象数量增长,则已经不可扩展),但实际上是因为需要根据查询,时间对每个对象应用一个或多个测试复杂度更准确的是O(nt),其中t是应用于每个对象的测试数。

因此,随着将额外对象添加到集合中和/或随着查询中的测试数量的增加,性能将降低。

还有另一种方法可以使用索引和集合理论。

一种方法是在存储在集合中的对象中的字段上构建索引,然后在查询中对其进行测试。

假设您有一个Car对象的集合,并且每个Car对象都有一个字段color。假设您的查询等效于"SELECT * FROM cars WHERE Car.color = 'blue'"。你可以在Car.color上构建一个索引,它基本上是这样的:

1
2
'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/

这里有一个例子:

寻找活跃的客户//(可转换的版本)

1
2
3
4
5
6
List<Customer> activeCustomers = new ArrayList<Customer>();  
for (Customer customer : customers) {  
  if (customer.isActive()) {  
    activeCusomers.add(customer);  
  }  
}

LambdaJ版本

1
2
List<Customer> activeCustomers = select(customers,
                                        having(on(Customer.class).isActive()));

当然,拥有这种美感会影响性能(有点......平均2次),但是你能找到更易读的代码吗?

它有许多功能,另一个例子可能是排序:

排序迭代

1
2
3
4
5
6
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
        public int compare(Person p1, Person p2) {
           return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
        }
});

用lambda排序

1
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());

继续Comparator主题,您可能还想查看Google Collections API。特别是,它们有一个名为Predicate的接口,它与Comparator具有类似的作用,因为它是一个简单的接口,可以被过滤方法使用,比如Sets.filter。它们包括一大堆复合谓词实现,用于执行AND,OR等。

根据数据集的大小,使用此方法比使用SQL或外部关系数据库方法更有意义。


如果需要单个具体匹配,则可以让类实现Comparator,然后创建一个包含所有散列字段的独立对象,并使用它来返回匹配的索引。当你想在集合中找到多个(可能的)对象时,你将不得不求助于像JoSQL这样的库(它在我用过它的琐碎案例中运行良好)。

一般来说,我倾向于将Derby嵌入到我的小应用程序中,使用Hibernate注释来定义我的模型类,让Hibernate处理缓存方案以保持一切快速。


我会使用一个比较年份和车牌模式作为输入参数的比较器。然后只需遍历您的集合并复制匹配的对象。您可能最终会使用这种方法制作一整套自定义比较器。


Comparator选项也不错,特别是如果你使用匿名类(以便不在项目中创建冗余类),但最终当你看到比较流程时,它就像你自己循环遍历整个集合一样,准确指定匹配项的条件:

1
2
3
4
5
6
if (Car car : cars) {
    if (1959 < car.getYear() && 1970 > car.getYear() &&
            car.getLicense().startsWith("AZ")) {
        result.add(car);
    }
}

然后是排序......这可能是背后的痛苦,但幸运的是有类Collections及其sort方法,其中一个接收Comparator ...


推荐阅读

    查询linux主机名命令?

    查询linux主机名命令?,系统,地址,工作,信息,网络,图片,名称,命令,电脑,标准,l

    linux清理内存命令行?

    linux清理内存命令行?,策略,数据,系统,名称,不了,管理,情况,工作,一致,时间,l

    linux分析内存命令?

    linux分析内存命令?,情况,系统,信息,分析,命令,地址,内存,工具,下来,数据,lin

    linux查询url命令?

    linux查询url命令?,系统,网址,工具,数据,网站,命令,传播,软件,地址,标准,linu

    linux的内存查看命令?

    linux的内存查看命令?,系统,情况,信息,数据,工具,命令,内存,第一,环境,电脑,

    linux清洁内存命令?

    linux清洁内存命令?,系统,软件,电脑,工具,情况,网络,缓存,内存,命令,管理,lin

    linux查询命令进程?

    linux查询命令进程?,系统,名称,总量,情况,状态,进程,材料,工具,电脑,数据,怎

    linux命令行查内存?

    linux命令行查内存?,系统,情况,信息,状态,工具,内存,电脑,分析,数据,命令,怎

    linux看剩余内存命令?

    linux看剩余内存命令?,系统,情况,工具,信息,分析,状态,实时,命令,内存,总量,L

    查询linux内存命令?

    查询linux内存命令?,系统,情况,信息,工具,电脑,状态,命令,内存,发行,总量,查

    linux命令查询屏保?

    linux命令查询屏保?,系统,工作,工具,信息,地址,图片,命令,目录,基础,电脑,lin

    linux查内存命令6?

    linux查内存命令6?,情况,系统,信息,工具,数据,内存,命令,单位,环境,方法,查看

    linux链路查询命令?

    linux链路查询命令?,系统,信息,工作,地址,命令,工具,时间,盘中,基础,名字,lin

    linux查询文件夹命令?

    linux查询文件夹命令?,系统,软件,电脑,命令,文件,文件夹,单位,第三,档案,数

    linux查询线程命令?

    linux查询线程命令?,系统,第一,线程,命令,进程,代码,分时,软件,选项,界面,如

    linux查询内核数命令?

    linux查询内核数命令?,系统,第一,信息,命令,实时,软件,电脑,内核,个数,界面,

    linux条件判断命令?

    linux条件判断命令?,代码,系统,语句,地方,工作,软件,时间,项目,管理,标准,条

    linux查询ip命令?

    linux查询ip命令?,地址,网络,信息,设备,系统,电脑,终端,命令,中心,技术指标,l

    linux查询所有命令?

    linux查询所有命令?,工作,地址,系统,命令,信息,目录,工具,基础,文件,内容,lin