Подтвердить что ты не робот

Есть ли способ избежать циклов при добавлении в список?

Мне было интересно, как выглядит такой код:

List<String> list = new ArrayList<String>();
for(CustomObject co : objects) {
    list.add(co.getActualText());
}

Можно ли написать иначе? Я имею в виду, конечно, в какой-то момент будет цикл, но мне интересно, есть ли использование API, которое я игнорирую

4b9b3361

Ответ 1

Если вы используете Java 8, вы можете воспользоваться Stream API:

List<String> list = objects.stream()
                           .map(CustomObject::getActualText)
                           .collect(Collectors.toList());

Ответ 2

Если у вас есть Java 8, как насчет:

objects.forEach(item -> list.add(item.getActualText()));

Внутренне все еще петля.

ИЗМЕНИТЬ немного Офф-Тема: ИМО Это наиболее читаемое и лучшее решение. Почему бы просто не использовать foreach, о котором вы могли бы спросить. Ответ: так как коллекция выбирает лучший способ перебора элементов. Например, ArrayList не использует итератор, потому что он лучше вас знает:

@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

Ответ 3

Конечно, Apache Commons и Guava также предоставляют способы избежать циклов без использования Java 8.

Commons CollectionUtils.collect:

CollectionUtils.collect(objects, Transformer.invokerTransformer("getActualText"), list);

Guava Lists.transform:

List<String> list = Lists.transform(objects, 
    new Function<CustomObject, String>() { 
        public String apply(CustomObject co) {
            return co.getActualText();
        }
    }
);

Ответ 4

Хотя это явно смехотворное предложение: вы можете избежать циклов, добавив их рекурсивно.

void add(List<? super String> receiver, CustomObject[] objects) {
  addRec(receiver, toAdd, 0, objects.length());
}

void addRec(List<? super String> receiver, CustomObject[] objects, int start, int end) {
  if (start + 1 == end) {
    receiver.add(objects[start].getActualText());
  } else if (start != end) {
    int mid = (start + end) / 2;
    addRec(receiver, objects, start, mid);
    addRec(receiver, objects, mid, end);
  }
}

Ответ 5

Если вы используете Eclipse Collections (ранее Коллекции GS), вы можете написать следующее в Java 8:

MutableList<CustomObject> objects = ...
MutableList<String> result = objects.collect(CustomObject::getActualText);

С помощью Java 5-7 вы можете использовать анонимный внутренний класс, представляющий тип SAM Function с помощью метода collect.

MutableList<CustomObject> objects = ...
MutableList<String> result = objects.collect(new Function<CustomObject, String>() {
    public String valueOf(CustomObject object){
        return object.getActualText();
    }
});

Примечание: Я являюсь коммиттером для коллекций Eclipse

Ответ 6

Использование потоков будет более идиоматичным в Java 8, но если вам нравится, чтобы он был ближе к обычным подходам на основе цикла, вы можете использовать forEach:

objects.forEach(co -> list.add(co.getActualText()) );

Ответ 7

Для достижения действительно хорошей эффективности при копировании диапазона данных между двумя типами списков, которые неизвестны друг другу, должен существовать механизм, с помощью которого "доверенный" тип может запрашивать у каждого из них, чтобы связать связанные с ним массивы поддержки с рядом элементов, а затем использовать операцию массовой копии для перемещения данных от одного к другому. Можно было бы полностью написать такой класс в Java, используя метод GetArraySource передать конструктору доверенного класса ArraySource объект, который он мог бы использовать для запроса массива поддержки, связанного с определенным элементом (возврат был бы включают в себя базовый массив и диапазон элементов, включенных в него). Код, требующий копию, вызовет GetArraySource и передаст ArraySource, возвращенный тем самым в метод назначения CopyFromArraySource, который затем может запросить ArraySource скопировать один или несколько диапазонов элементов в свой собственный массив поддержки (s).

Если ArraySource был классом, поставляемым с Java, и Oracle точно документировал, что он будет делать с полученными массивами, тогда типы, такие как ArrayList и String, могли бы показать их содержимое как ArraySource или принимать внешние данные из ArraySource, не подвергая их массив любому коду, который может его нарушить.

К сожалению, если Oracle не включит такую ​​вещь в дистрибутив Java, поддержка, вероятно, будет слишком скудной, чтобы быть полезной. Нехорошо, чтобы исходный список поддерживал один такой класс, назначение - другое, а код, требующий операции копирования, - третий. Все три класса должны поддерживать один и тот же класс доверенных массивов-сегментов-копий-помощников.