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

发布于 2024-08-20 07:44:16 字数 654 浏览 9 评论 0原文

我有几个如下所示的对象:

class PhoneNumber
{
   String   getNumber();
   String   getExtension();
   DateTime getLastCalled();
}
class Address
{
   String getCity();
   string getState();
   int    getZip();
}

我希望能够获取其中任何一个对象的列表并获取特定属性的列表。如果我要为每个属性编写一个函数,这是一个微不足道的操作,但据我了解,多次重复代码是不好的做法。

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

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

我绞尽脑汁试图用泛型来执行此操作。我什至不确定这是否可能,但据我了解,使用 Java 编程语言可以完成很多神奇的事情。

I have several objects that look like this:

class PhoneNumber
{
   String   getNumber();
   String   getExtension();
   DateTime getLastCalled();
}
class Address
{
   String getCity();
   string getState();
   int    getZip();
}

I'd like to be able to take a List of any one of those objects and get a list of a particular property. This is a trivial operation if I were to write a function for each property, but as I understand it, it is bad practice to duplicate code so many times.

So I would like to be able to do something like this for any property in either object:

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

I've racked my brain trying to do this with generics. I'm not even sure that this is possible, but as I understand it, a lot of magical things can be done with the Java programming language.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

顾忌 2024-08-27 07:44:16

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

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

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);

You can do this with generics and a utility class to do the work. I like this a little bit better than using reflection because you get compile time checking that the property you're retrieving exists (and isn't misspelled etc.).

First a class that does the actual conversion. Note the abstract "get" method which we'll override in an anonymous inner class when we call getListOfProperties().

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;
  }
}

Then you use it like this. Not a pretty one liner, but compile time checking goodness:

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);
影子的影子 2024-08-27 07:44:16

对于如此简单的事情,您最好只提供 getter 和 setter。拒绝重复一行代码并不能节省太多。更好的是,只需让您的 IDE 为您编写即可。

For something this simple, you're better off just providing the getters and setters. You're not saving much by refusing to duplicate one line of code. Even better, just get your IDE to write it for you.

相权↑美人 2024-08-27 07:44:16

您可以使用 Introspector 处理对象 就像这个答案< /a>.

public <T > List<T > getMemberList( List<? > beanList, 
        String propertyName, Class<T > resultClass ) throws Exception {
    List<T > result = new ArrayList<T >();
    for( Object bean : beanList ) {
        result.add( (T )new PropertyDescriptor( 
                propertyName, bean.getClass() ).getReadMethod().invoke( bean ) );
    }
    return result;
}

然后你可以像这样调用:

List<String > result = getMemberList( phonenumberList, "number", String.class );

You could handle your objects with Introspector like in this SO answer.

public <T > List<T > getMemberList( List<? > beanList, 
        String propertyName, Class<T > resultClass ) throws Exception {
    List<T > result = new ArrayList<T >();
    for( Object bean : beanList ) {
        result.add( (T )new PropertyDescriptor( 
                propertyName, bean.getClass() ).getReadMethod().invoke( bean ) );
    }
    return result;
}

Then you can do a call like this:

List<String > result = getMemberList( phonenumberList, "number", String.class );
淡笑忘祈一世凡恋 2024-08-27 07:44:16

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

You can use reflection (java.lang.Class and java.lang.reflect.*), to get method names; those beginning with "get" are properties, whose name follows "get".

千纸鹤 2024-08-27 07:44:16

这是 Java 中闭包的一个很好的例子;它即将到来,但尚未到来。

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

通过使用 Apache Commons BeanUtils 库,这种类型的事情得到了极大的简化。

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;
}

This is a pretty good case for closures in Java; it's coming, but it's not here yet.

In the meantime, you can do this with reflection, although reflection always has a performance penalty. One of the things reflection can do is to let you call a method on an object, or retrieve a property, by specifying the name of the method/property as a string; in your case you would want to do getListOfProperties(AddressList, "city") and within that method use reflection to retrieve the specified property.

This type of thing is simplified dramatically by using the Apache Commons BeanUtils library.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文