Как я могу вызвать метод для каждого элемента списка?
Предположим, что у меня есть список автомобилей:
public class Car {
private String brand;
private String name;
private String color;
public Car() { // ... }
public getName() { return name; }
// ...
}
// Suppose that I have already init the list of car
List<Car> cars = //...
List<String> names = new ArrayList<String>();
for (Car c : cars ) {
names.add(c.getName());
}
Как я могу сократить код выше? Вкратце, Как я могу вызвать метод для каждого элемента списка?
Например, в Python:
[car.name for car in cars]
Ответы
Ответ 1
ОБНОВИТЬ:
Смотрите ответ aaiezza для решения Java 8 с использованием лямбда-выражения.
Оригинальный ответ до Java 8:
Эффект может быть достигнут с Guava, реализация Function
уже более многословна, чем у вас:
List<Car> cars = //...
Function<Car, String> carsToNames = new Function<Car, String>() {
@Override
public String apply(Car car) {
return car.getName();
}
}
List<String> names = Lists.transform(cars, carsToNames);
(Имейте в виду, что Lists.transform
возвращает представление, которое будет применять функцию лениво - если вы хотите немедленное копирование, вам нужно скопировать возвращенный список в новый список.)
Так что это не поможет вам сократить ваш код, но это пример того, насколько он многословен для достижения желаемого эффекта в Java.
Редактировать: Вы можете взглянуть на lambdaj, библиотеку, которая, кажется, подходит к тому, что вы ищете. Я не пробовал это сам, но на домашней странице показан этот пример:
List<Person> personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma"));
forEach(personInFamily).setLastName("Fusco");
Ответ 2
Java 8 (надеюсь) будет иметь некоторую форму лямбда-выражения, которая сделает такой код более выполнимым. (Будет ли что-то вроде понимания списка - это другой вопрос.)
Ваше желание было исполнено!
---РЕДАКТИРОВАТЬ---
лол как будто на реплике: forEach()
Определенно проверьте это.
Для вашего вопроса конкретно, это становится следующим:
// Suppose that I have already init the list of car
List<Car> cars = //...
List<String> names = new ArrayList<String>();
// LAMBDA EXPRESSION
cars.forEach( (car) -> names.add(car.getName()) );
Это действительно невероятно, что они сделали здесь. Я рад видеть это в будущем.
---РЕДАКТИРОВАТЬ---
Я должен был увидеть это раньше, но я не могу удержаться, кроме как написать об этом.
Функциональность Stream, добавленная в jdk8, позволяет использовать метод map.
// Suppose that I have already init the list of car
List<Car> cars = //...
// LAMBDA EXPRESSION
List<String> names = cars.stream().map( car -> car.getName() ).collect( Collectors.toList() );
Еще более кратким было бы использование ссылок на методы Java 8 (oracle doc).
List<String> names = cars.stream().map( Car::getName ).collect( Collectors.toList() );
Ответ 3
кроме как избавиться от брекетов и/или переместить весь код в одну строку, что может быть не очень хорошая идея, вы не можете.
Ответ 4
Если вы застряли и все еще должны использовать Apache Commons, то класс Transformer может помочь: http://apachecommonstipsandtricks.blogspot.de/2009/01/examples-of-functors-transformers.html
Ответ 5
В common- lisp есть карта-функция (это не имеет ничего общего с приведенным выше примером автомобиля).
Общая карта-функция в Java:
static <LIST_TYPE, ELEM_TYPE> List<LIST_TYPE> mapcar(Collection<ELEM_TYPE> list, Function<ELEM_TYPE, LIST_TYPE> function)
{
return list.stream().map(function).collect(Collectors.toList());
}
Для автомобильного примера:
List<String> carNames = mapcar(cars, car -> car.getName());