如何在列表的每个元素上调用lambda并将结果放入新列表中?我的工作版本太冗长了

use*_*001 5 java boilerplate java-8 java-stream

我想在List的每个元素上调用lambda函数,并将结果放在一个新的List中.

我目前的版本是这样的:

b = a.stream().map(i-> i+1).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

但它似乎相当冗长,并且通过从列表到流的转换所需的所有样板代码隐藏了代码的意图,反之亦然.其他语言(例如ruby)中的相同代码将更加简洁,如下所示:

b = a.map{|i| i+1}
Run Code Online (Sandbox Code Playgroud)

当然可以做这样的事情:

for (int i: a) {
    b.add(i+1);
}
Run Code Online (Sandbox Code Playgroud)

但它看起来有点过时,而且不如lambda版本灵活.

为了改变现有的List,Holger的评论 list.replaceAll(i->i+1)很好,但我有兴趣创建一个新的List对象.

是否有一种方法可以在列表的每个元素上调用lambda并创建一个带有结果的新元素?

fgb*_*fgb 8

为了更简洁,您可以使用Stream API的某个包装器,或者完全绕过它.你可以实现类似的东西:

class ListUtil {
    public static <A, B> List<B> map(List<A> list, Function<? super A, ? extends B> f) {
        List<B> newList = new ArrayList<>(list.size());
        for(A a:list) {
            newList.add(f.apply(a));
        }
        return newList;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用静态导入,您可以编写:

b = map(a, i -> i + 1);
Run Code Online (Sandbox Code Playgroud)


Jam*_*s_D 5

我会忽略与其他语言的比较,因为1.我对它们不熟悉,而且2.我认为理解你所要求的语言哲学可能更有帮助.

请记住,列表和流是根本不同的东西.列表(和其他集合)是内存中包含有限数量元素的实体.它包含对所有这些元素的引用.

相反,流是一个(可能是无限的)值序列,可以在运行中生成和消耗.在任何给定时间都不一定引用所有元素(甚至任何元素).

因此,为列表实现"映射"不同于为流实现"映射".对于流,概念是"在生成元素时,将函数应用于它们,并生成函数的结果".这使用API​​直接支持Stream.map().

对于列表,等效的概念是"给我一个列表,其元素i是将函数应用于原始列表的元素i的结果".API不支持此功能,但实现起来非常简单:

import java.util.AbstractList;
import java.util.List;
import java.util.function.Function;

/**
 *  Provides a view of a source list with a function applied to each element.
 *  This list is unmodifiable.
 *
 * @param <S> The type of the elements in the source list.
 * @param <T> The type of the elements in the mapped list.
 */
public class MappedList<S, T> extends AbstractList<T> {

    private final List<S> source ;
    private final Function<S,T> map ;

    public MappedList(List<S> source, Function<S,T> map) {
        this.source = source ;
        this.map = map ;
    }

    @Override
    public T get(int index) {
        return map.apply(source.get(index));
    }

    @Override
    public int size() {
        return source.size();
    }

}
Run Code Online (Sandbox Code Playgroud)

您将使用如下:

List<Integer> original = ... ;
List<Integer> originalPlusOne = new MappedList<>(original, i -> i+1);
Run Code Online (Sandbox Code Playgroud)

如果希望代码更简洁,可以添加静态工厂方法MappedList:

public static <S,T> MappedList<S,T> mapOf(List<S> source, Function<S,T> map) {
    return new MappedList<S,T>(source, map);
}
Run Code Online (Sandbox Code Playgroud)

然后就是

List<Integer> originalPlusOne = MappedList.mapOf(original, i -> i+1);
Run Code Online (Sandbox Code Playgroud)

要么

List<Integer> originalPlusOne = mapOf(original, i -> i+1);
Run Code Online (Sandbox Code Playgroud)

如果你使用静态导入.

请注意,映射列表是不可修改的,因此

originalPlusOne.add(42);
Run Code Online (Sandbox Code Playgroud)

将抛出一个异常(这是合适的,因为如果成功,将违背这个主意originalPlusOne包含的所有元素original1加入到他们); 并注意它是原始列表的视图,因此添加元素original将添加元素originalPlusOne.你当然可以这样做

List<Integer> originalPlusOne = new ArrayList<>(new MappedList<>(original, i -> i+1));
Run Code Online (Sandbox Code Playgroud)

生成一个独立于原始列表的可修改列表.