【发布时间】:2014-04-14 01:36:45
【问题描述】:
我经常想将一个列表映射到另一个列表。例如,如果我有一个人员列表,并且我想要他们的姓名列表,我想这样做:
目标
List<Person> people = ... ;
List<String> names = people.map(x -> x.getName());
Java 8 可以实现这样的事情:
JAVA 8 版本
List<String> names = people.stream()
.map(x -> x.getName())
.collect(Collectors.toList());
但这显然不是那么好。其实我觉得用番石榴更干净:
番石榴版本
List<String> names = Lists.transform(people, x -> x.getName());
但是,我确实喜欢链接。那么,我的目标可行吗?
我听说有人说 Java 8 默认方法类似于 C# 扩展方法。使用 C# 扩展方法,我可以轻松地将辅助方法添加到 IEnumerable<T>:
public static IEnumerable<TRet> Map<T, TRet>(this IEnumerable<T> list, Func<T, TRet> selector)
{
return list.Select(selector);
}
但是我不知道如何使用默认方法来扩展现有接口。
另外,这显然是一个微不足道的例子。一般来说,我希望能够扩展List<T> 和Iterable<T> 接口,以使与流API 的交互更容易。
【问题讨论】:
-
请注意
collect(Collectors.toList())将返回一个副本,而Lists.transform返回一个视图。 -
您可以随时创建自己的接口并创建类似于
transform(list).using(x -> x.getName())的代码 -
仅供参考:使用
Foo::getName代替x -> x.getName()会更简单。 -
@LouisWasserman 是的,我可以做到。不过,我仍在决定是否更喜欢 lambda 语法……截至目前,我认为开发人员发现 lambdas 比方法引用更容易阅读,尤其是来自 coffeescript 或 C# 或其他什么的时候。
-
@Alden,Java 类型系统不如 Scala 那样富有表现力,而且 Java 不是一种动态语言,因此(语言和库的作者)不可能改进API 做你想做的事,而不会失去灵活性(例如简单的并行性和惰性)或向现有接口添加 huge 膨胀(例如,他们要直接将
map方法添加到List类)。而且由于 Java 没有提供任何扩展现有类型的方法,因此您实际上陷入了困境。对不起:(
标签: java lambda guava java-8 default-method