添加到列表时有没有办法避免循环?

时间:2015-03-19 22:13:05

标签: java list arraylist data-structures collections

我想知道这样的代码:

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

可以用不同的方式书写吗?我的意思是当然在某些时候会有一个循环,但我想知道是否有一个我忽略的API使用

7 个答案:

答案 0 :(得分:27)

如果您使用Java 8,则可以利用Stream API:

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

答案 1 :(得分:20)

如果你有Java 8,那么:

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

虽然在内部仍然是一个循环。

编辑一点偏离主题:IMO这是最具可读性和最佳解决方案。为什么不使用你可能会问的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();
    }
}

答案 2 :(得分:9)

当然,Apache Commons和Guava也提供了在不使用Java 8的情况下避免循环的方法。

Commons CollectionUtils.collect

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

番石榴Lists.transform

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

答案 3 :(得分:6)

虽然显然有点荒谬的建议:你可以通过递归添加来避免循环。

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);
  }
}

答案 4 :(得分:4)

如果您使用Eclipse Collections(以前为GS Collections),您可以在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 Collections的提交者

答案 5 :(得分:3)

在Java 8中使用流将更加惯用,但如果您希望它更接近传统的基于循环的方法,您可以使用forEach

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

答案 6 :(得分:0)

为了在彼此不知道的两种类型的列表之间复制一系列数据时实现非常好的效率,必须有一种机制,通过该机制,一个&#34;信任&#34; type可以让每个人公开与一系列元素相关联的后备数组,然后使用批量复制操作将数据从一个元素移动到另一个元素。可以通过将GetArraySource方法传递给受信任ArraySource类的构造函数来完全用Java编写这样的类,该对象可用于请求与特定元素关联的后备数组(返回将包括后备数组和其中包含的元素范围)。想要复制的代码会调用GetArraySource,然后将返回的ArraySource传递到目标列表的CopyFromArraySource方法,然后可以要求ArraySource复制一个或更多范围的项目到其自己的支持数组中。

如果ArraySource是一个Java提供的类,并且Oracle准确记录了它对它收到的数组的作用,那么ArrayListString等类型就可以将其内容公开为ArraySource,或接受来自ArraySource的外部数据,而不会将其数组不正当地暴露给可能滥用它的任何代码。

不幸的是,除非Oracle将这样的东西整合到Java发行版中,否则支持可能太稀疏而无法使用。让源列表支持一个这样的类,目标支持另一个,以及希望复制操作的代码是第三个,这是不好的。所有这三个类都需要支持相同的特定trusted-array-segment-copy-helper类。