Java Bipredicate的类型安全容器

Java Bipredicate的类型安全容器,java,oop,generics,design-patterns,wildcard,Java,Oop,Generics,Design Patterns,Wildcard,我有一个设计问题,我不知道如何解决。 我创建了一个计算解析表达式的计算器类。表达式的形状为amount>50。运算符用于理解必须创建哪个谓词。然后,LHS被发送到另一个对象以获取其实际值。该值可以是字符串、整数、双精度等。 当我尝试创建相应的谓词并用适当的值初始化它时,问题就开始了。我得到警告,它是不安全的类型,使用原始类型等。我想解决这个问题,如果我可以和不抑制警告。我目前的想法是创建一个容器类,我将其命名为Value,这是通用的。但我一直坚持这一思路。我的代码: public class

我有一个设计问题,我不知道如何解决。 我创建了一个计算解析表达式的
计算器
类。表达式的形状为
amount>50
。运算符用于理解必须创建哪个谓词。然后,LHS被发送到另一个对象以获取其实际值。该值可以是
字符串
整数
双精度
等。 当我尝试创建相应的
谓词
并用适当的值初始化它时,问题就开始了。我得到警告,它是不安全的类型,使用原始类型等。我想解决这个问题,如果我可以和不抑制警告。我目前的想法是创建一个容器类,我将其命名为
Value
,这是通用的。但我一直坚持这一思路。我的代码:


public class Evaluator {
    static PredicateFactory predFactory = new PredicateFactory();


    public boolean evaluate(String[] expression, Data data){ // currently doesn't actually work, just testing
        BiPredicate predicate = predFactory.createPred(expression[1]);
        predicate.test(data.getAttribute(expression[0]), 50);
    }
}

public class PredicateFactory {


    public BiPredicate<?,?> createPred(String operator) {
        return switch (operator) {
            case "<" -> (BiPredicate<Double, String>) (i, j) -> i <  Double.parseDouble(j);
            case ">" -> (BiPredicate<Double, String>) (i, j) -> i >  Double.parseDouble(j);
            case "from domain" -> (BiPredicate<String, String>) (i, j) -> i.endsWith("@" + j);
            default -> null;
        };
    }

public class Value<T>{
    private T val;

    Value(T val){
        this.val = val;
    }

    public T getVal(){
        return this.val;
    }
}


public class Data {
    private int id;
    private int total_price;
    private String date;
    private String email;
   ....

    Data(int id, int price, String date, String email, ){
        this.id = id;
        this.total_price = price;
        this.date = date;
        this.email = email;
.....
    }

    public Value<?> getAttribute(String attribute){ 
        return switch(attribute){
            case "value" -> new Value<>((double) this.total_price);
            case "email" -> new Value<>(this.email);
            default -> null;
        };

    }
}



公共类评估员{
静态PredicateFactory predFactory=新的PredicateFactory();
公共布尔求值(字符串[]表达式,数据){//目前实际上不起作用,只是测试
BiPredicate谓词=predFactory.createPred(表达式[1]);
test(data.getAttribute(表达式[0]),50);
}
}
公共类谓词属性{
公共双预测createPred(字符串运算符){
返回开关(操作员){
格“->(双预测)(i,j)->i>Double.parseDouble(j);
案例“来自域”->(双预测)(i,j)->i.endsWith(“@”+j”);
默认->空;
};
}
公共阶级价值{
私人旅行社;
值(T val){
this.val=val;
}
公共T getVal(){
返回此.val;
}
}
公共类数据{
私有int-id;
私人国际总价格;
私有字符串日期;
私人字符串电子邮件;
....
数据(整数id、整数价格、字符串日期、字符串电子邮件等){
this.id=id;
此项。总价=价格;
this.date=日期;
this.email=电子邮件;
.....
}
公共值getAttribute(字符串属性){
返回开关(属性){
案例“价值”->新价值(双倍于此总价);
案例“email”->新值(this.email);
默认->空;
};
}
}
感谢您的指点

您可以:

public BiPredicate<Object, Object> createPred(String operator) {
    return switch (operator) {
        case "<" -> (i, j) -> (Double) i < Double.parseDouble((String) j);
        case ">" -> (i, j) -> (Double) i > Double.parseDouble((String) j);
        case "from domain" -> (i, j) -> ((String) i).endsWith("@" + j);
        default -> null;
    };
}
public-BiPredicate-createPred(字符串运算符){
返回开关(操作员){
大小写“”->(i,j)->(Double)i>Double.parseDouble((String)j);
大小写“来自域”->(i,j)->((String)i).endsWith(“@”+j);
默认->空;
};
}
或者使用包装器/持有者类(但这需要为每个值创建一个额外的实例,这意味着它的效率不高。因此我更喜欢上面提到的实现):

public-BiPredicate-createPred(字符串运算符){
返回开关(操作员){
大小写“”->(i,j)->i.number>Double.parseDouble(j.string);
大小写“from domain”->(i,j)->i.string.endsWith(“@”+j.string”);
默认->空;
};
}
公共静态类持有者{
公众双倍号码;
公共字符串;
公众持有人(双倍号码){
这个数字=数字;
}
公众持有人(字符串){
this.string=string;
}
}

如果您确定只会输入正确的类型(作为调用谓词时的参数),那么抑制警告应该是完全正确的,您不必担心。否则,您可以使用“Object”作为谓词的类型,然后使用“instanceof”检查labda(谓词)中对象的类型。这应该会使警告消失,但如果永远不会有不正确的输入,这将是不必要的。感谢@intovid的回复,我肯定会输入正确的类型。我完全可以控制这一点。但是,抑制警告不是一个坏的编码习惯吗?我想避免长时间切换:instanceofs、feels over的情况y复杂且不可缩放这就是为什么我建议使用对象作为谓词的类型,然后在labda中将对象强制转换为您需要的任何类型。如果未使用instanceof,则当输入错误的参数时,它将抛出错误(这很好,因为您可以直接知道代码是否会产生输入错误数据类型的状态)(如果不使用instanceof,则可能会出现另一个警告,但这次是在labda内部,而不是在调用它的位置)。我真的想不出另一个不需要包装器类的解决方案。
oop
标记似乎放错了地方。在oop中,数据和逻辑是结合在一起的。这里数据和逻辑是分开的。也许目标是函数式编程?@intovid我会尝试使用Object,但我很想听听你对包装器的意见-我不是非常有经验,并试图使这个设计尽可能最好,所以如果它是一个好的设计,我愿意实现我必须实现的。@jaco0646,你可能是对的-虽然我只是在这个特定的情况下分离数据和逻辑。你认为
数据
类处理布尔求值逻辑更有意义吗?
public BiPredicate<Holder, Holder> createPred(String operator) {
    return switch (operator) {
        case "<" -> (i, j) -> i.number < Double.parseDouble(j.string);
        case ">" -> (i, j) -> i.number > Double.parseDouble(j.string);
        case "from domain" -> (i, j) -> i.string.endsWith("@" + j.string);
        default -> null;
    };
}

public static class Holder {
    public double number;
    public String string;

    public Holder(double number) {
        this.number = number;
    }

    public Holder(String string) {
        this.string = string;
    }
}