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