gpt4 book ai didi

java - 如何在运行时过滤 java 对象列表,其中我要过滤的变量事先未知?

转载 作者:行者123 更新时间:2023-11-30 05:39:42 25 4
gpt4 key购买 nike

我有一个java对象列表,我想在运行时使用流来过滤它们。但是,我想要过滤的变量只有在运行时才知道。

例如,用户说我想要一个所有毛皮长度超过 3 厘米的猫的列表,我应该能够做到

cats.stream().filter(cat -> cat.getFurLength() > 3).collect(Collectors.toList());

然而, getFurLength() getter 应该动态调用 - 如果用户想按眼睛颜色过滤,那么我应该能够调用

cats.stream().filter(cat -> cat.getEyeColour() == Colour.BLUE).collect(Collectors.toList());

如何在不事先编写所有可能的过滤器的情况下实现此目的?

理想情况下,用户应该发送如下内容:

{
eyeColour:{
operator: "equal_to",
value: "BLUE"
},
furLength: {
operator: "greater_than",
value: 3
}
}

并且代码应该能够根据这些条件动态生成过滤器。

最佳答案

假设您的 Cat 类遵循 JavaBean 约定,您可以使用 java.beans.PropertyDescriptor 根据属性名称访问 getter Method

这使我们能够了解我们正在处理什么类型的值。如果它是数字,我们可以处理 greater_than 和其他运算符,但如果它是非数字,我们应该只处理 equals_to 运算符。

“简化”且非常有限的解决方案可能如下所示:

注意:
- 解决方案不支持原始数字类型,例如int。请改用 IntegerDouble 等。
- 我将所有数字转换为 BigDecimal 并使用compareTo 来简化数字类型比较,如果您遇到大数字或非常精确的数字的任何错误,请随时将其替换为正确的数字类型比较)。
- 对于相等性检查,它会比较对象的字符串表示形式(toString() 的结果),因此对于 Color,您不能使用 BLUE,但您的 JSON 需要保存 java.awt.Color[r=0,g=0,b=255])

class PredicatesUtil {

static <T> Predicate<T> filters(Class<T> clazz, String filtersJson) {

JSONObject jsonObject = new JSONObject(filtersJson);

List<Predicate<T>> predicateList = new ArrayList<>();
for (String property : jsonObject.keySet()) {
JSONObject filterSettings = jsonObject.getJSONObject(property);

try {
String operator = filterSettings.getString("operator");
String value = filterSettings.getString("value");
predicateList.add(propertyPredicate(clazz, property, operator, value));
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
return combinePredicatesUsingAND(predicateList);
}

static <T> Predicate<T> combinePredicatesUsingAND(List<Predicate<T>> predicateList) {
return t -> {
for (Predicate<T> pr : predicateList) {
if (!pr.test(t))
return false;
}
return true;
};
}

static <T> Predicate<T> propertyPredicate(Class<T> clazz, String property,
String operator, String value)
throws IntrospectionException {

final Method m = new PropertyDescriptor(property, clazz).getReadMethod();
final Class<?> returnType = m.getReturnType();

return obj -> {
try {
Object getterValue = m.invoke(obj);
if (Number.class.isAssignableFrom(returnType)) {
BigDecimal getValue = new BigDecimal(getterValue.toString());
BigDecimal numValue = new BigDecimal(value);

int compared = getValue.compareTo(numValue);
if (operator.equalsIgnoreCase("equal_to")) {
return compared == 0;
} else if (operator.equalsIgnoreCase("lesser_than")) {
return compared < 0;
} else if (operator.equalsIgnoreCase("greater_than")) {
return compared > 0;
} else {
throw new RuntimeException("not recognized operator for numeric type: " + operator);
}
} else {
//System.out.println("testing non-numeric, only euals_to");
if (operator.equalsIgnoreCase("equal_to")) {
return value.equalsIgnoreCase(getterValue.toString());
}
throw new RuntimeException("not recognized operator: " + operator);
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
}

可以这样使用:

class Cat {
private Color eyeColour;
private Integer furLength;

Cat(Color eyeColor, Integer furLength) {
this.eyeColour = eyeColor;
this.furLength = furLength;
}

public Color getEyeColour() {
return eyeColour;
}

public Integer getFurLength() {
return furLength;
}

public void setEyeColour(Color eyeColour) {
this.eyeColour = eyeColour;
}

public void setFurLength(Integer furLength) {
this.furLength = furLength;
}

@Override
public String toString() {
return "Cat{" +
"eyeColor=" + eyeColour +
", furLength=" + furLength +
'}';
}
}
class CatsDemo {
public static void main(String[] args) {

String json =
"{\n" +
" eyeColour:{\n" +
" operator: \"equal_to\",\n" +
" value: \"java.awt.Color[r=0,g=0,b=255]\"\n" +
" },\n" +
" furLength: {\n" +
" operator: \"greater_than\",\n" +
" value: \"3\"\n" +
" }\n" +
"}";

List<Cat> cats = List.of(
new Cat(Color.blue, 1),
new Cat(Color.blue, 2),
new Cat(Color.blue, 3),
new Cat(Color.blue, 4),
new Cat(Color.blue, 5),
new Cat(Color.yellow, 1),
new Cat(Color.yellow, 2),
new Cat(Color.yellow, 3),
new Cat(Color.yellow, 4),
new Cat(Color.yellow, 5)
);

cats.stream()
.filter(PredicatesUtil.filters(Cat.class, json))
.forEach(System.out::println);
}
}

输出:

Cat{eyeColor=java.awt.Color[r=0,g=0,b=255], furLength=4}
Cat{eyeColor=java.awt.Color[r=0,g=0,b=255], furLength=5}

关于java - 如何在运行时过滤 java 对象列表,其中我要过滤的变量事先未知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55891819/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com