假设我有一个像下面这样的bean。
class Customer{
private String code;
private String name;
private Integer value;
//getters setters omitted for brevity
}
然后从一个方法我得到一个List<Customer>
。现在让我们说我想从列表中获取所有成员“名称”的列表。显然,我可以自己遍历并构建一个List<String>
元素“name”。
但是,我想知道这种技术是否有捷径或更有效的方法,任何人都知道。例如,如果我想获取Map对象中所有键的列表,我会得到map.keySet()。这条线上的东西是我想要找到的东西。
答案 0 :(得分:6)
Guava有Lists.transform
可以使用提供的Function<F,T>
(或更确切地说,List<F>
)将List<T>
转换为Function<? super F,? extends T>
。
来自文档:
public static <F,T> List<T> transform( List<F> fromList, Function<? super F,? extends T> function )
返回将
function
应用于fromList
的每个元素的列表。返回的列表是fromList
的转换视图;对fromList
的更改将反映在返回的列表中,反之亦然。
function
懒惰地应用,在需要时调用。
类似的实时视图转换也提供如下:
Iterables.transform
(Iterable<F>
至Iterable<T>
)Iterators.transform
(Iterator<F>
至Iterator<T>
)Collections2.transform
(Collection<F>
至Collection<T>
)Maps.transformValues
(Map<K,V1>
至Map<K,V2>
)答案 1 :(得分:5)
看起来你正在寻找与Perl的map
函数相当的Java。这种事情可能会被添加到集合库中一次(如果)Java接收闭包。在那之前,我认为这是你能做的最好的事情:
List<String> list = new ArrayList<String>(customers.size());
for ( Customer c : customers ) {
list.add(c.getName());
}
您还可以编写一个map
函数,该函数使用简单的接口来提供映射函数。像这样:
public interface Transform<I, O> {
O transform(I in);
}
public <I, O> List<O> map(Collection<I> coll, Transform<? super I, ? extends O> xfrm) {
List<O> list = new ArrayList<O>(coll.size());
for ( I in : coll ) {
list.add(xfrm.transform(in));
}
return list;
}
答案 2 :(得分:4)
可以使用这样的东西: http://code.google.com/p/lambdaj/
答案 3 :(得分:3)
我认为这是你必须在循环中自己编码的东西。
答案 4 :(得分:2)
您可以使用LambdaJ的Converter界面,并拥有以下一行:
List<String> customerNames = convert(customerList, new Converter<Customer,String>() {
public String convert(Customer customer) {
return customer.getName();
}
});
答案 5 :(得分:2)
您需要使用循环,但您正在寻找的函数在函数式语言中称为map
。在Java中实现map
是可能的,尽管它往往相当不优雅;这是我很久以前在我的“Java应该有的东西,但由于某种原因没有”库中实现的版本:
public interface MapFunction<T, U> {
public U map(T source);
}
public static <T, U> U[] map(T[] objects, MapFunction<T, U> f) {
if(objects.length == 0) {throw new IllegalArgumentException("Can't map onto an empty array");}
@SuppressWarnings("unchecked") U[] rtn = (U[])Array.newInstance(f.map(objects[0]).getClass(), objects.length);
for(int i = 0; i < objects.length; i++)
rtn[i] = f.map(objects[i]);
return rtn;
}
使用它,你可以这样做:
List<Customer> list = yourFunction();
List<String> names = Arrays.asList(map(list.toArray(new Customer[0]), new MapFunction<Customer, String>() {
public String map(Customer c) {
return c.getName();
}
}));
您可以自然地将地图更改为采集而不是数组,这样就无需Arrays.asList
和List.toArray
答案 6 :(得分:2)
使用Guava,您可以使用Function以及Iterables.transform,Collections2.transform或Lists.transform来创建Iterable
,{{1分别为{}}或Collection
。
List
返回的Iterable<String> names = Iterables.transform(customers,
new Function<Customer, String>() {
public String apply(Customer from) {
return from.getName();
}
});
是惰性的,并在迭代它时将函数应用于基础列表。对于包含名称的Iterable
,您可以使用:
List<String>
或
List<String> names = Lists.transform(...);
当然,每次要执行此操作时写出匿名内部类ImmutableList<String> names = ImmutableList.copyOf(Iterables.transform(...));
实现都是丑陋且冗长的,因此您可能希望Function
可以使Function
成为常量例如,名为Customer
的类。
然后转换看起来更好(尤其是静态导入):
Customer.NAME
我还写过关于在对象的特定属性(例如for (String name : transform(customers, Customer.NAME)) { ... }
)中使用接口来帮助在我的博客here上整合这些功能。
答案 7 :(得分:1)
....是否有捷径或更有效的方式
那么,您是否正在寻找一种更有效的方法来实现这一目标:
List<String> names = new ArrayList<String>();
for( Customer customer : yourCustomerList ) {
names.add( customer.getName() );
}
?!!!!
或只是 不同的 方式?
以前的所有答案在运行时和编码方面都没有那么高效。然而,毫无疑问,它们更具弹性。
另一种选择是在Java代码中包含 Scala Groovy并使用它:
<击> list.map( _.name )
击>
list.collect { it.name }
如果编译,可以从Java使用Groovy类,或者您可以将它们作为脚本插入。
以下是使用Groovy作为脚本的给定Customer
类的示例。
List<Customer> customers = Arrays.asList( new Customer[]{
new Customer("A","123",1),
new Customer("B","456",2),
new Customer("C","789",3),
new Customer("D","012",4)
});
setVariable(customers, "list");
evaluate("names = list.collect { it.name } ");
List<String> names = (List<String>) getVariable("names");
System.out.println("names = " + names);
输出:
names = [A, B, C, D]
注意:我提取了方法以便于阅读,但您可以在
下面看到它们但是,这又是不同的,并不比常规for循环更有效。
这是complete source code。要运行它,您只需要在类路径中使用Java1.6和Groovy。