Is there a way to avoid loops when adding to a list?

大城市里の小女人 提交于 2020-06-24 10:55:06

问题


I was wondering a code like this:

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

Can it be written differently? I mean of course at some point there will be a loop but I am wondering if there is an API usage I am ignoring


回答1:


If you use Java 8, you can take advantage of the Stream API:

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



回答2:


If you have Java 8, what about:

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

Internally still a loop though.

EDIT a little Off-Topic: IMO This is the most readable and best solution. Why not just use a foreach you might ask. The answer: Because this way the collection chooses the best way to iterate over the items. For example, ArrayList does not use an iterator, because it knows better than you:

@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:


Of course, Apache Commons and Guava also provide ways to avoid loops without using 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:


Although clearly a bit of a ridiculous suggestion: you could avoid loops by adding them recursively.

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:


If you use Eclipse Collections you can write the following as of Java 8:

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

With Java 5 - 7 you can use an anonymous inner class representing the SAM type Function with the collect method.

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

Note: I am a committer for Eclipse Collections




回答6:


Using streams would be more idiomatic in Java 8, but if you like it to be closer to the conventional loop based approach you can use forEach:

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



回答7:


To achieve really good efficiency when copying a range of data between two types of lists that are unknown to each other, there must be a mechanism by which a "trusted" type can ask each to expose the backing array(s) associated with a range of elements, and then use a bulk-copy operation to move data from one to the other. It would be possible to write such a class entirely in Java, by having a GetArraySource method pass to the constructor of a trusted ArraySource class an object it could use to request the backing array associated with a particular element (the return would include the backing array and the range of elements included therein). The code wanting the copy would call GetArraySource, and pass the ArraySource returned thereby to the destination list's CopyFromArraySource method which could then ask the ArraySource to copy one or more ranges of items into its own backing array(s).

If ArraySource was a class supplied with Java, and Oracle documented exactly what it would do with arrays that it received, then it would be possible for types like ArrayList and String to expose their contents as an ArraySource, or accept outside data from an ArraySource, without improperly exposing their array to any code that might abuse it.

Unfortunately, unless Oracle incorporates such a thing into the Java distribution, support will probably be too sparse to be useful. It does not good to have the source list support one such class, the destination support another, and the code wanting the copy operation a third. All three classes need to support the same particular trusted-array-segment-copy-helper class.



来源:https://stackoverflow.com/questions/29155970/is-there-a-way-to-avoid-loops-when-adding-to-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!