Java中的类似Python的列表推导式

72 投票
7 回答
66668 浏览
提问于 2025-04-15 11:47

因为Java不允许把方法当作参数传递,所以你会用什么方法在Java中实现像Python那样的列表推导呢?

我有一个字符串的列表(ArrayList)。我需要用一个函数来处理每个元素,这样我就能得到另一个列表。我有几个函数,它们的输入是一个字符串,输出也是一个字符串。我想做一个通用的方法,可以把列表和函数作为参数传进去,这样我就能得到一个处理过的列表。虽然从字面上看这不太可能,但我应该用什么方法呢?

另外一个选择是为每个小的字符串处理函数写一个新的函数,这个函数简单地遍历整个列表,但这样做就显得没那么酷了。

7 个回答

17

Google Collections库提供了很多类,可以帮助我们更高效地处理集合和迭代器,比起普通的Java支持的功能要强大得多,而且它的使用方式也更像函数式编程(比如过滤、映射、折叠等)。这个库定义了Function和Predicate这两个接口,并提供了一些方法,利用这些接口来处理集合,这样你就不需要自己去写这些处理逻辑了。此外,它还提供了一些方便的函数,让你在使用Java的泛型时不那么麻烦。

我还会使用Hamcrest来过滤集合。

这两个库可以很容易地通过适配器类结合在一起使用。


** 说明:我参与了Hamcrest的编写

85

在Java 8中,你可以使用方法引用:

List<String> list = ...;
list.replaceAll(String::toUpperCase);

或者,如果你想创建一个新的列表实例:

List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
38

基本上,你需要创建一个函数接口:

public interface Func<In, Out> {
    public Out apply(In in);
}

然后把一个匿名子类传递给你的方法。

你的方法可以选择对每个元素进行原地处理:

public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) {
    ListIterator<T> itr = list.listIterator();
    while (itr.hasNext()) {
        T output = f.apply(itr.next());
        itr.set(output);
    }
}
// ...
List<String> myList = ...;
applyToListInPlace(myList, new Func<String, String>() {
    public String apply(String in) {
        return in.toLowerCase();
    }
});

或者创建一个新的 List(简单来说,就是把输入列表映射到输出列表):

public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) {
    List<Out> out = new ArrayList<Out>(in.size());
    for (In inObj : in) {
        out.add(f.apply(inObj));
    }
    return out;
}
// ...
List<String> myList = ...;
List<String> lowerCased = map(myList, new Func<String, String>() {
    public String apply(String in) {
        return in.toLowerCase();
    }
});

哪种方式更好,取决于你的具体需求。如果你的列表非常大,原地处理可能是唯一可行的办法;如果你想对同一个原始列表应用很多不同的函数,生成多个衍生列表,那么你就需要使用 map 版本。

撰写回答