7

Let's say there is a class:

class Person
{
   String name;
   int age;
   City location;
}

Is there some library that will let me create a list of Strings containing each name from the list of persons in one line instead of creating a new list and looping through the other list?

Something like:

List<Person> people = getAllOfThePeople();
List<String> names = CoolLibrary.createList("name", people);

Rather than:

List<Person> people = getAllOfThePeople();
List<String> names = new LinkedList<String>();
for(Person person : people)
{
    names.add(person.getName());
}
2
  • If only Java had LINQ natively.. No, this is not possible. Maybe it is supported in Java 8, but it certainly isn't prior to that. It's doable with reflection ofcourse, but there's no built-in querying option. Commented Dec 3, 2013 at 21:48
  • Appears too specific but you can write one using reflection and generics to make the output strongly typed.. Commented Dec 3, 2013 at 21:49

2 Answers 2

18

You can using Java 8 with lambda expressions :

List<String> listNames = people.stream().map(u -> u.getName()).collect(Collectors.toList());

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

public class Test {
  public static void main(String args[]){
    List<Person> people = Arrays.asList(new Person("Bob",25,"Geneva"),new Person("Alice",27,"Paris"));
    List<String> listNames = people.stream().map(u -> u.getName()).collect(Collectors.toList());
    System.out.println(listNames);
  }
}
class Person
{
   private String name;
   private int age;
   private String location;

  public Person(String name, int age, String location){
    this.name = name;
    this.age = age;
    this.location = location;
  }

  public String getName(){
    return this.name;
  }

}

Output :

[Bob, Alice]

Demo here.


Alternatively, you can define a method that will take your list as parameter and the function you want to apply for each element of this list :

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 just do :

List<String> lNames = processElements(people, p -> p.getName()); //for the names
List<Integer> lAges = processElements(people, p -> p.getAge()); //for the ages
//etc.

If you want to group people by age, the Collectors class provide nice utilities (example):

Map<Integer, List<Person>> byAge = people.stream()
                                         .collect(Collectors.groupingBy(Person::getAge));
Sign up to request clarification or add additional context in comments.

Comments

4

You can do a little trick using Guava library (which I consider the ultimate Java library that you should be using anyway):

class Person
{
   String name;
   int age;
   City location;

  public static final Function<Person, String> getName = new Function<Person, String>() {
    public String apply(Person person) {
      return person.name;
    }
  }
}


List<Person> people = getAllOfThePeople();
List<String> names = FluentIterable.from(people).transform(Person.getName).toList();

The trick is defining the getName public static Function in the Person class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.