Java中类Python的列表理解

由于Java不允许传递方法作为参数,你使用什么技巧来实现像Java中的列表理解一样的Python?

我有一个列表(ArrayList)的string。 我需要通过使用函数来转换每个元素,以便我得到另一个列表。 我有几个函数将一个string作为input,并返回另一个string作为输出。 我如何做一个generics的方法,可以给列表和函数作为参数,以便我可以得到每个处理元素的列表。 在字面意义上是不可能的,但是我应该使用什么技巧?

另一个select是为每个较小的string处理函数编写一个新的函数,它只是在整个列表上循环,这不是很酷。

基本上,你创build一个function界面:

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

或创build一个新的List (基本上创build从input列表到输出列表的映射):

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

哪一个更好取决于你的用例。 如果您的清单非常大,就地解决scheme可能是唯一可行的解​​决scheme; 如果您希望将许多不同的function应用于相同的原始列表以制作多个派生列表,则需要map版本。

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

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

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

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

Google Collections库有许多用于处理集合和迭代器的类,它们的级别远高于普通Java支持的级别,并且具有function性(filter,映射,折叠等)的function。 它定义了函数和谓词接口和使用它们来处理集合的方法,所以你不必这样做。 它也有便利的function,使处理Javagenerics不那么艰难。

我也使用Hamcrest **来过滤集合。

这两个库很容易与适配器类相结合。


**感兴趣的声明:我与Hamcrest合着

Apache Commons CollectionsUtil.transform(Collection,Transformer)是另一种select。

我正在构build这个项目来编写Java中的列表理解,现在是https://github.com/farolfo/list-comprehension-in-java中的概念validation

例子

 // { x | x E {1,2,3,4} ^ x is even } // gives {2,4} Predicate<Integer> even = x -> x % 2 == 0; List<Integer> evens = new ListComprehension<Integer>() .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // evens = {2,4}; 

如果我们想以某种方式来转换输出expression式

 // { x * 2 | x E {1,2,3,4} ^ x is even } // gives {4,8} List<Integer> duplicated = new ListComprehension<Integer>() .giveMeAll((Integer x) -> x * 2) .suchThat(x -> { x.belongsTo(Arrays.asList(1, 2, 3, 4)); x.is(even); }); // duplicated = {4,8} 

你可以使用lambdas作为函数,就像这样:

 class Comprehension<T> { /** *in: List int *func: Function to do to each entry */ public List<T> comp(List<T> in, Function<T, T> func) { List<T> out = new ArrayList<T>(); for(T o: in) { out.add(func.apply(o)); } return out; } } 

用法:

 List<String> stuff = new ArrayList<String>(); stuff.add("a"); stuff.add("b"); stuff.add("c"); stuff.add("d"); stuff.add("cheese"); List<String> newStuff = new Comprehension<String>().comp(stuff, (a) -> { //The <String> tells the comprehension to return an ArrayList<String> a.equals("a")? "1": (a.equals("b")? "2": (a.equals("c")? "3": (a.equals("d")? "4": a ))) }); 

将返回:

 ["1", "2", "3", "4", "cheese"]