我将ViewValue类定义如下:
class ViewValue {
private Long id;
private Integer value;
private String description;
private View view;
private Double defaultFeeRate;
// getters and setters for all properties
}
在我的代码中,我需要将ViewValue实例列表转换为包含相应ViewValue的id字段值的列表。
我使用foreach循环来做到这一点:
List<Long> toIdsList(List<ViewValue> viewValues) {
List<Long> ids = new ArrayList<Long>();
for (ViewValue viewValue : viewValues) {
ids.add(viewValue.getId());
}
return ids;
}
有没有更好的方法解决这个问题?
答案 0 :(得分:33)
你可以使用Commons BeanUtils和Collections在一行中完成:
(为什么在其他人为您完成代码时编写您自己的代码?)
import org.apache.commons.beanutils.BeanToPropertyValueTransformer;
import org.apache.commons.collections.CollectionUtils;
...
List<Long> ids = (List<Long>) CollectionUtils.collect(viewValues,
new BeanToPropertyValueTransformer("id"));
答案 1 :(得分:28)
使用谷歌收藏。例如:
Function<ViewValue, Long> transform = new Function<ViewValue, Long>() {
@Override
public Long apply(ViewValue from) {
return from.getId();
}
};
List<ViewValue> list = Lists.newArrayList();
List<Long> idsList = Lists.transform(list, transform);
<强>更新强>
在Java 8上,您不需要Guava。你可以:
import com.example.ViewValue;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
Function<ViewValue, Long> transform = ViewValue::getId;
List<ViewValue> source = new ArrayList<>();
List<Long> result = source.stream().map(transform).collect(Collectors.toList());
或者只是:
List<ViewValue> source= new ArrayList<>();
List<Long> result = source.stream().map(ViewValue::getId).collect(Collectors.toList());
NEXT UPDATE(Javaslang之后的最后一个改名为Vavr):
目前值得一提的是使用 Javaslang库(http://www.javaslang.io/) Vavr库(http://www.vavr.io/)的解决方案。让我们假设我们的列表包含真实对象:
List<ViewValue> source = newArrayList(new ViewValue(1), new ViewValue(2), new ViewValue(2));
我们可以使用Javaslang库中的List类进行转换(从长远来看,收集不方便):
List<Long> result = io.vavr.collection.List.ofAll(source).map(ViewValue::getId).toJavaList();
但是你会看到只有Javaslang列表的力量:
io.vavr.collection.List<ViewValue> source = javaslang.collection.List.of(new ViewValue(1), new ViewValue(2), new ViewValue(3));
io.vavr.collection.List<Long> res = source.map(ViewValue::getId);
我鼓励在该库上查看可用的集合和新类型(我特别喜欢Try类型)。您可以在以下地址找到文档: http://www.javaslang.io/javaslang-docs/ http://www.vavr.io/vavr-docs/。
PS。由于Oracle和名称中的“Java”字,他们必须将库名从javaslang更改为其他名称。他们决定让Vavr。
答案 2 :(得分:28)
我们可以使用java 8
在一行代码中完成List<Long> ids = viewValues.stream().map(ViewValue::getId).collect(Collectors.toList());
了解详情: Java 8 - Streams
答案 3 :(得分:27)
编辑:这个答案是基于这样的想法,即您需要为代码中的其他实体和其他属性执行类似的操作。如果仅需要将ViewValues列表转换为ID列表,请坚持使用原始代码。但是,如果您想要一个更可重用的解决方案,请继续阅读......
我会为投影声明一个界面,例如
public interface Function<Arg,Result>
{
public Result apply(Arg arg);
}
然后你可以编写一个通用的转换方法:
public <Source, Result> List<Result> convertAll(List<Source> source,
Function<Source, Result> projection)
{
ArrayList<Result> results = new ArrayList<Result>();
for (Source element : source)
{
results.add(projection.apply(element));
}
return results;
}
然后你可以像这样定义简单的投影:
private static final Function<ViewValue, Long> ID_PROJECTION =
new Function<ViewValue, Long>()
{
public Long apply(ViewValue x)
{
return x.getId();
}
};
并按照以下方式应用它:
List<Long> ids = convertAll(values, ID_PROJECTION);
(显然使用K&amp; R支撑和更长的线条会使投影声明更短一些:)
坦率地说,所有这些对于lambda表达式来说会更好,但不要介意......
答案 4 :(得分:4)
我为这个用例实现了一个小函数库。其中一种方法有这个签名:
<T> List<T> mapToProperty(List<?> objectList, String property, Class<T> returnType)
它接受字符串并使用反射来创建对属性的调用,然后它返回由objectList支持的List,其中使用此属性调用实现get和iterator。
mapToProperty函数是根据一般的map函数实现的,该函数将Function作为映射器,就像描述的另一篇文章一样。非常有用。
我建议你阅读基本的函数编程,特别是看看Functors(实现map函数的对象)
编辑:反思确实不一定非常昂贵。 JVM在这方面有了很大的改进。只需确保编译一次调用并重复使用它。
Edit2:示例代码
public class MapExample {
public static interface Function<A,R>
{
public R apply(A b);
}
public static <A,R> Function<A,R> compilePropertyMapper(Class<A> objectType, String property, Class<R> propertyType)
{
try {
final Method m = objectType.getMethod("get" + property.substring(0,1).toUpperCase() + property.substring(1));
if(!propertyType.isAssignableFrom(m.getReturnType()))
throw new IllegalArgumentException(
"Property "+property+" on class "+objectType.getSimpleName()+" is not a "+propertyType.getSimpleName()
);
return new Function<A,R>()
{
@SuppressWarnings("unchecked")
public R apply(A b)
{
try {
return (R)m.invoke(b);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T1,T2> List<T2> map(final List<T1> list, final Function<T1,T2> mapper)
{
return new AbstractList<T2>()
{
@Override
public T2 get(int index) {
return mapper.apply(list.get(index));
}
@Override
public int size() {
return list.size();
}
};
}
@SuppressWarnings("unchecked")
public static <T1,T2> List<T2> mapToProperty(List<T1> list, String property, Class<T2> propertyType)
{
if(list == null)
return null;
else if(list.isEmpty())
return Collections.emptyList();
return map(list,compilePropertyMapper((Class<T1>)list.get(0).getClass(), property, propertyType));
}
}
答案 5 :(得分:3)
你可以使用包装器:
public class IdList impements List<Long>
{
private List<ViewValue> underlying;
pubic IdList(List<ViewValue> underying)
{
this.underlying = underying;
}
public Long get(int index)
{
return underlying.get(index).getId()
}
// other List methods
}
虽然这是更乏味的工作,但它可以提高性能。
你也可以使用反射来实现你和我的解决方案,但这对于穿孔来说非常糟糕。
我不担心Java中没有简短易用的通用解决方案。在Groovy中,你只需使用collect(),但我相信这也涉及到反射。
答案 6 :(得分:2)
这取决于您对List<Long>
以及List<ViewValue>
例如,您可以通过创建自己的包含List<ViewValue>
的List实现来获得足够的功能,使用遍历ViewValues的迭代器实现来实现iterator()
,并返回id。
答案 7 :(得分:0)
您可以通过以下对象列表的属性(例如,id为键,某些属性为值)填充地图
Map<String, Integer> mapCount = list.stream().collect(Collectors.toMap(Object::get_id, Object::proprty));