当从对象列表中获取每个对象中的属性列表时,Java可以防止代码重复

当从对象列表中获取每个对象中的属性列表时,Java可以防止代码重复,java,generics,code-duplication,Java,Generics,Code Duplication,我有几个像这样的对象: class PhoneNumber { String getNumber(); String getExtension(); DateTime getLastCalled(); } class Address { String getCity(); string getState(); int getZip(); } List<String > result = getMemberList( phonenum

我有几个像这样的对象:

class PhoneNumber
{
   String   getNumber();
   String   getExtension();
   DateTime getLastCalled();
}
class Address
{
   String getCity();
   string getState();
   int    getZip();
}
List<String > result = getMemberList( phonenumberList, "number", String.class );
我希望能够获取这些对象中任何一个的列表,并获取特定属性的列表。如果我要为每个属性编写一个函数,这是一个微不足道的操作,但据我所知,重复代码太多次是一种不好的做法

因此,我希望能够对任一对象中的任何属性执行类似的操作:

List<Address> AddressList = getAddresses();
List<String> CityList = getListOfProperties( AddressList, Address.getCity /*<--Instruction as to what property to populate the returned list with */ )
List AddressList=getAddresses();

List CityList=getListOfProperties(AddressList,Address.getCity/*您可以用类似的方式处理对象


public List getMemberList(List对于这么简单的东西,最好只提供getter和setter。拒绝复制一行代码不会节省太多。更好的是,让您的IDE为您编写它。

您可以使用反射(java.lang.Class和java.lang.reflect.*),以获取方法名称;以“get”开头的是属性,其名称在“get”之后。

这是Java中闭包的一个很好的例子;它即将出现,但还没有出现

同时,您可以通过反射来实现这一点,尽管反射总是会带来性能损失。反射可以做的一件事是让您通过将方法/属性的名称指定为字符串来调用对象上的方法或检索属性;在您的情况下,您需要执行
getListOfProperties(AddressList,“city”)
并在该方法中使用反射来检索指定的属性

通过使用这个库,这类事情被大大简化了

import org.apache.commons.beanutils.beanutils;
静态列表getListOfProperties(列表bean、字符串propertyName){
List PropertyValue=new ArrayList();
for(对象bean:bean){
add(BeanUtils.getProperty(bean,propertyName));
}
返回属性值;
}

您可以使用泛型和实用程序类来完成这项工作。与使用反射相比,我更喜欢这样做,因为您可以在编译时检查正在检索的属性是否存在(并且没有拼写错误等)

首先是一个进行实际转换的类。请注意抽象的“get”方法,当我们调用getListOfProperties()时,我们将在匿名内部类中重写该方法

公共抽象类ListPropertyGetter
{
/**给定源对象,返回类型为R.*/
公共摘要R-get(T源);
/**给定一个对象列表,使用“get”方法检索单个属性
并返回这些属性值的列表*/
公共最终列表getListOfProperties(列表)
{
List ret=newarraylist(List.size());
对于(T来源:列表)
{
ret.add(get(source));
}
返回ret;
}
}
然后像这样使用它。不是一个漂亮的单行程序,而是编译时检查:

List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
// add some PhoneNumbers to the list
List<String> extensions =
  new ListPropertyGetter<String, PhoneNumber>()
  {
    @Override
    public String get(PhoneNumber source)
    {
      return source.getExtension();
    }
  }.getListOfProperties(phoneNumbers);
List phoneNumbers=new ArrayList();
//在列表中添加一些电话号码
列表扩展=
新的ListPropertyGetter()
{
@凌驾
获取公共字符串(电话号码源)
{
返回source.getExtension();
}
}.getListOfProperties(电话号码);

Man,在我放弃并发布这个问题之前,我已经非常接近类似的东西了。非常感谢!您的
ListPropertyGetter
类是通用的,足以对输入项执行任何操作以生成输出项,而不仅仅是获取属性。这通常称为
map
(除了在Linq中,它被称为
Select
)。一旦您提供了访问器方法,您就会邀请代码复制。
import org.apache.commons.beanutils.BeanUtils;

static List<String> getListOfProperties(List beans, String propertyName) {
    List<String> propertyValues = new ArrayList<String>();
    for (Object bean:beans) {
         propertyValues.add(BeanUtils.getProperty(bean, propertyName));
    }
    return propertyValues;
}
public abstract class ListPropertyGetter<R,T>
{
  /** Given a source object, returns some property of type R. */ 
  public abstract R get(T source);

  /** Given a list of objects, use the "get" method to retrieve a single property
      from every list item and return a List of those property values. */
  public final List<R> getListOfProperties(List<T> list)
  {
    List<R> ret = new ArrayList<R>(list.size());
    for(T source : list)
    {
      ret.add(get(source));
    }
    return ret;
  }
}
List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
// add some PhoneNumbers to the list
List<String> extensions =
  new ListPropertyGetter<String, PhoneNumber>()
  {
    @Override
    public String get(PhoneNumber source)
    {
      return source.getExtension();
    }
  }.getListOfProperties(phoneNumbers);