问题
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