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

时间:2022-07-29 14:14:34

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

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

7 个解决方案

#1


27  

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

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

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

#2


20  

If you have Java 8, what about:

如果你有Java 8,那么:

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:

编辑一点偏离主题: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();
    }
}

#3


9  

Of course, Apache Commons and Guava also provide ways to avoid loops without using Java 8.

当然,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


6  

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


4  

If you use Eclipse Collections (formerly GS Collections) you can write the following in Java 8:

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

使用Java 5 - 7,您可以使用表示SAM类型函数的匿名内部类和collect方法。

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

注意:我是Eclipse Collections的提交者

#6


3  

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:

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

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

#7


0  

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).

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

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.

如果ArraySource是一个Java提供的类,并且Oracle确切地记录了它对它接收的数组的作用,那么像ArrayList和String这样的类型可以将它们的内容公开为ArraySource,或者接受来自ArraySource的外部数据,没有不正当地将他们的数组暴露给任何可能滥用它的代码。

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.

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

#1


27  

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

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

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

#2


20  

If you have Java 8, what about:

如果你有Java 8,那么:

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:

编辑一点偏离主题: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();
    }
}

#3


9  

Of course, Apache Commons and Guava also provide ways to avoid loops without using Java 8.

当然,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


6  

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


4  

If you use Eclipse Collections (formerly GS Collections) you can write the following in Java 8:

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

使用Java 5 - 7,您可以使用表示SAM类型函数的匿名内部类和collect方法。

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

注意:我是Eclipse Collections的提交者

#6


3  

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:

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

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

#7


0  

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).

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

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.

如果ArraySource是一个Java提供的类,并且Oracle确切地记录了它对它接收的数组的作用,那么像ArrayList和String这样的类型可以将它们的内容公开为ArraySource,或者接受来自ArraySource的外部数据,没有不正当地将他们的数组暴露给任何可能滥用它的代码。

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.

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