3

Let's say I have this class.

class People { private String name; private int age; /** other stuff constructor / getters / setters / etc. **/ } 

And let's say I have this list :

List<People> people = Arrays.asList(new People("Mark", 21), new People("Bob",17), new People("Alex", 22)); 

Now I want to be able to get a List for all users of a particular attribute.

Using Java 8, I can create a method that accepts the function I want like :

public static <X, Y> List<Y> processElements(Iterable<X> source, Function <X, Y> mapper) { List<Y> l = new ArrayList<>(); for (X p : source) l.add(mapper.apply(p)); return l; } 

Then I will able to perform some calls like :

List<String> listNames = processElements(people, p -> p.getName()); List<Integer> listAges = processElements(people, p -> p.getAge()); 

However this is not possible in Java 7 (I know that it exists in Guava, but I would come up with a solution only using the JDK).

This is with what I come up using reflection :

public static List<Object> processElements(List<People> l, String fieldName) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{ Field field = People.class.getDeclaredField(fieldName); field.setAccessible(true); List<Object> list = new ArrayList<>(); for(People p : l){ list.add(field.get(p)); } field.setAccessible(false); return list; } 

Now I can do something like List<Object> listNames = processElements(people, "name"); which works quite well.

But I don't feel comfortable with it :

  1. I'm getting a List<Object>
  2. Whenever I use reflection, I always feel like it exists a better implementation not using it
  3. Using field.setAccessible(true); is not very secure

So my questions are :

  1. Is it possible to do the same thing without using reflection with the JDK (not using Guava or Functional Java) ?
  2. How can I get a List of String or Integer according to the type of the field I pass as parameter to my method ?

Thanks

3
  • Maybe a simple Map<String, Object> map suits your needs? Commented Dec 8, 2013 at 16:24
  • A simple for loop will do: List<String> result = new ArrayList<>(); for (People p : list) { result.add(p.getName()); }. What's the problem with this obvious solution? And if Guava does it, why wouldn't you be able to do it? Commented Dec 8, 2013 at 16:30
  • 1
    @JBNizet Good point for "if Guava does". I would just trying to make an all-in-one function that can return me the attribute I want for all my objects in a List. Commented Dec 8, 2013 at 17:26

2 Answers 2

6

You can do the exact same thing you were trying to do with Java 8 using an anonymous class with Java 7

public static <X, Y> List<Y> processElements(Iterable<X> source, Function <X, Y> mapper) { List<Y> l = new ArrayList<>(); for (X p : source) l.add(mapper.apply(p)); return l; } List<String> listNames = processElements(people, new Function<People, String>() { public String apply(People person) { return person.getName(); } }); 
Sign up to request clarification or add additional context in comments.

6 Comments

But he stated that he wants a solution for Java 7
@Ben This is the alternative with Java 7. Implement your own Function interface.
My fault, before the edit your introduction text was a bit misleading :D 1+ of course.
How couldn't I know about implementing my own Function interface.. Thanks dude, you rock !
@SotiriosDelimanolis: No, it's not the same thing at runtime. An additional class is not created, a new instance is not created every time either, invokedynamic is used... and the whole thing is more efficient. It's actually much more than syntactic sugar.
|
2

In Java 8, you would do it as follows:

List<String> names = people.stream() .map(Person::getName).collect(Collectors.asList()); 

Your Java 8 solution works in Java 7 too as it does not use any special language construct but only the interface Function, which is introduced in Java 8. If you need such an interface, you can simply declare it by yourself!

public interface Function<T, R> { R apply(T t); } 

8 Comments

-1: There is no stream() method in List. There is also no operator like :: in Java.
@MartijnCourteaux: there is one in Java 8.
Sorry, guys. My bad. I don't know anything about the new Java 8. Looks like Java is evolving into a super dynamic language that makes abstraction of what is going on underneath. The stream, map, collect methods are scaring me. It doesn't feels "pure" anymore.
@MartijnCourteaux A lot of influence from functional programming languages.
I've the felt like Java 8 is very influencated by Scala
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.