按对象属性值查找

时间:2012-11-18 13:54:34

标签: java collections properties


我有以下情况。我有一些A类,它有B类对象列表。 类型B有两个属性X,Y为string类型,两个getter为getX()getY()。 我希望在A类中有一个方法,它从由给定的string值选择的B对象的集合中返回一个对象。例如:

B findElementByX(String x) {
    for (B i : list) {
         if (i.getX().equals(x)
             return i;
    }
    return null;
}

对于其他属性Y我将拥有几乎相同的代码,btu而不是getX(),将有getY()。对我来说,它是不必要的代码冗余。我的问题是:如何编写这个方法,以便通过X或Y属性值找到一个方法?这是用Java解决这个问题的通用方法吗?

3 个答案:

答案 0 :(得分:4)

你可以有一个功能

B findElementByProperty(String prop, PropertyExtractor<B,String> propEx)

其中PropertyExtractor<B,P>是指向B返回类型P的函数的泛型函数指针。

只是Java没有函数指针。所以PropertyExtractor<B,P>可以是一个单一方法的接口,比如P getProperty(B obj),你当然需要两个实现(分别包含对getXgetY的调用)。

但是,您可以很容易地看到,这不会为您节省很多代码。相反。

答案 1 :(得分:2)

你可以通过Guava之类的东西来减少像这样的事情的代码大小,它提供类似于功能语言风格列表理解的东西。

您也可以通过定义界面

自行完成其中一些操作
public interface Predicate<T> {
    boolean apply(T obj);
}

然后使用它创建一个finder方法:

B findElementByPredicate(Predicate<B> predicate) {
    for (B b : list) {
        if (predicate.apply(b))
            return b;
    }
    return null;
}

您还可以(如评论中所述)使用反射来获取字段的值。实现arne.b的答案中定义的接口,您可以定义

public class ReflectivePropertyExtractor<T, P> implements PropertyExtractor<T, P> {

    String fieldName;

    public ReflectivePropertyExtractor(String fieldName) {
        this.fieldName = fieldName;
    }

    @Override
    public P getProperty(T obj) {
        try {
            Method m = B.class.getMethod(makeAccessorName());
            return (P) m.invoke(obj);
        } catch (InvocationTargetException e) {
            return null;
        } catch (NoSuchMethodException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    private String makeAccessorName() {
        return "get" + capitalize(fieldName);
    }

    private String capitalize(String s) {
        if ((s == null) || (s.length() == 0))
            return s;
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

}

创建一个适用于指定字段名称的属性提取器,并按照他在答案中描述的那样使用它,或者根据它创建一个谓词:

public class PropertyMatchPredicate<T, P> implements Predicate<T> {
    private final P matchValue;
    private final PropertyExtractor<T, P> extractor;

    public PropertyMatchPredicate(P matchValue, PropertyExtractor<T, P> extractor) {
        this.matchValue = matchValue;
        this.extractor = extractor;
    }

    @Override
    public boolean apply(T obj) {
        return matchValue.equals(extractor.getProperty(obj));
    }
}

然后在findByPredicate上面使用该谓词:

B findElementByProperty(String matchField, final String matchValue) {
    final ReflectivePropertyExtractor<B, String> extractor = new ReflectivePropertyExtractor<B, String>(matchField);
    return findElementByPredicate(new PropertyMatchPredicate<B, String>(matchValue, extractor));
}

如果您只处理两个属性,所有这些策略都可能会增加代码大小而不是减少代码大小。优势只会在更大范围内发生,并且您可能会为不熟悉功能风格和/或反思的人员降低代码的可读性付出代价。

答案 2 :(得分:1)

将X或Y作为另一个参数传递以查找getX()或getY(),否则返回null。

B findElementByXY(String s,String identifier) {
    for (X i : list)
    {
         if ("X".equals(identifier)&&i.getX().equals(s))
             return i;
         else if ("Y".equals(identifier)&&i.getY().equals(s))
             return i;

    }
    return null;
}