Java 从hashmap中查找具有可变数量属性(一个或多个)的对象
假设我们有person类:Java 从hashmap中查找具有可变数量属性(一个或多个)的对象,java,reflection,compare,Java,Reflection,Compare,假设我们有person类: class Person{ long id; String username; String password String firstName; String lastName; String address; String phoneNumber; // setters and getters.. } 我们有一个hashmap,其中包含personhashmap类型的对象,字符串是对象的用户名 我想搜索具有指定属性的对象(一个或多个),例如: 用户名:jim5
class Person{
long id;
String username;
String password
String firstName;
String lastName;
String address;
String phoneNumber;
// setters and getters..
}
我们有一个hashmap,其中包含personhashmap
类型的对象,字符串是对象的用户名
我想搜索具有指定属性的对象(一个或多个),例如:
用户名:jim54地址:英国
或
名:吉米,姓:托纳伯恩,地址:波兰
或
居住在英国的人(地址:英国)
没有编写大量重载方法
我的方法使用反射来查找单个属性的变体:
Method getter=getDeclaredMethodIgnoreCase(Person.class,"get"+"attribute");
Method setter=getDeclaredMethodIgnoreCase(Person.class,"set"+"attribute");
然后比较并更改首先,按用户名进行查找 简单地做:
Map<String,Person> people = new HashMap<>();
Person person = people.get("jim54");
例如,查找名为John
(忽略大小写)和姓为tornabone
(也忽略大小写)的所有人,地址包含Poland
字符串(也忽略大小写):
第一个方法接收一个函数,该函数从对象中提取属性,然后根据该属性检查条件。第二种方法简单地将所有给定的谓词合并成一个谓词,从而简化它们
现在可以使用第一种方法,如下所示:
Predicate<Person> condition = SearchUtils.extractThenFilter(
Person::getAddress,
address -> address.toLowerCase().contains("uk"));
List<Person> matching = people.values().stream()
.filter(condition)
.collect(Collectors.toList());
Predicate condition=SearchUtils.extractThenFilter(
Person::getAddress,
address->address.toLowerCase().contains(“uk”);
列表匹配=people.values().stream()
.过滤器(条件)
.collect(Collectors.toList());
这相当于上面的第一次搜索
以下内容相当于上述第二次搜索:
Predicate<Person> condition = SearchUtils.and(
SearchUtils.extractThenFilter(
Person::getFirstName,
str -> "John".equalsIgnoreCase(str)),
SearchUtils.extractThenFilter(
Person::getLastName,
"tornabone"::equalsIgnoreCase), // just another way
SearchUtils.extractThenFilter(
Person::getAddress,
str -> str.toLowerCase().contains("poland")));
List<Person> matching = people.values().stream()
.filter(condition)
.collect(Collectors.toList());
Predicate condition=SearchUtils.and(
SearchUtils.extractThenFilter(
Person::getFirstName,
str->“John”。等信号情况(str)),
SearchUtils.extractThenFilter(
Person::getLastName,
“tornabone”::equalsIgnoreCase),//另一种方式
SearchUtils.extractThenFilter(
Person::getAddress,
str->str.toLowerCase().contains(“波兰”);
列表匹配=people.values().stream()
.过滤器(条件)
.collect(Collectors.toList());
正如您所看到的,现在,对于两种不同的搜索,以完全相同的方式对映射值进行流式处理、对复合条件进行过滤以及收集到列表。我们已经将不同搜索的复杂性抽象为一个谓词
现在,如果您有一个将属性名称与属性提取器函数相匹配的映射,以及一些接收字符串并创建不同谓词的帮助器方法(例如,一个用于检查给定字符串是否包含在另一个字符串中,另一个用于检查是否忽略大小写相等,等等),然后您只需要解析搜索字符串,就可以完成了
编辑:
该接口是在Java8中引入的。它是一个函数接口,这意味着lambda表达式和方法引用可以针对它
在这里,我使用了例如Person::getAddress
作为一个函数,将Person
的实例转换为其地址。在extractThenFilter
实用程序方法中调用extractor.apply(t)
时,会调用Person.getAddress
方法,其中t
是Person
类的实例。然后,从Person
实例中提取的地址被传递给谓词(条件)。由于提取的地址类型为String
,因此give谓词接收该字符串并检查其是否满足条件(以下是同一示例,它检查Person
类小写字母实例的提取地址是否包含“uk”
)
您可以查看和以供进一步参考。您能否提供一些关于在通用方法中使用“函数”接口的参考?我还是不完全明白it@user2962142
java.util.function.function
是在Java8中引入的。它是一个函数接口,这意味着lambda表达式和方法引用可以针对它。在这里,我使用了例如Person::getAddress
作为一个函数,将Person
的实例转换为其地址。您可以查看和以获得进一步的参考。@user2962142我已经添加了一些解释。希望现在更清楚了。我建议您阅读本教程、javadocs以及其他关于函数和谓词的问题!这是你付出的巨大努力,学到了很多,尽管它仍然不能解决不知道要检查的属性的想法,因为用户提供了一个包含属性的字符串,即“地址”,所以我不能像Person::get+“Address”或其他什么样,但总的来说,你的回答很棒@用户2962142不客气!但是,你知道,从例如“address”
到Person::getAddress
非常简单:你所需要的只是一张地图。您可以这样填充它:map.put(“address”,Person::getAddress)
,等等。然后,您只需在映射上使用get:函数提取器=map.get(“address”)
public static <T, S> Predicate<T> extractThenFilter(
Function<T, S> extractor,
Predicate<S> condition) {
return t -> condition.test(extractor.apply(t));
}
public static <T> Predicate<T> and(Predicate<T>... conditions) {
return Arrays.stream(conditions)
.reduce(Predicate::and)
.orElse(t -> true);
}
Predicate<Person> condition = SearchUtils.extractThenFilter(
Person::getAddress,
address -> address.toLowerCase().contains("uk"));
List<Person> matching = people.values().stream()
.filter(condition)
.collect(Collectors.toList());
Predicate<Person> condition = SearchUtils.and(
SearchUtils.extractThenFilter(
Person::getFirstName,
str -> "John".equalsIgnoreCase(str)),
SearchUtils.extractThenFilter(
Person::getLastName,
"tornabone"::equalsIgnoreCase), // just another way
SearchUtils.extractThenFilter(
Person::getAddress,
str -> str.toLowerCase().contains("poland")));
List<Person> matching = people.values().stream()
.filter(condition)
.collect(Collectors.toList());