假设Student类如下:
class Student { private int no; private String name; public int getNo() { return no; } public String getName() { return name; } }
java中获取Student对象链表的方法为:
List<Student> getStudents(){ ... return studentList; }
在scala中获取no = 1 的student的name:
getStudents().find(_.getNo == 1).map(_.getName)
复杂例子:
函数式编程鼓励使用流水线转换将一个不可变的集合塑造为想要的结果。这常常会有非常简明的方案,但也容易迷糊读者——很难领悟作者的意图,或跟踪所有隐含的中间结果。例如,我们想要从一组语言中汇集不同的程序语言的投票,按照得票的顺序显示(语言,票数):
val votes = Seq(("scala", 1), ("java", 4), ("scala", 10), ("scala", 1), ("python", 10)) val orderedVotes = votes .groupBy(_._1) .map { case (which, counts) => (which, counts.foldLeft(0)(_ + _._2)) }.toSeq .sortBy(_._2) .reverse
上面的代码简洁并且正确,但几乎每个读者都不能理解作者的原本意图。一个策略是声明中间结果和参数:
val votesByLang = votes groupBy { case (lang, _) => lang } val sumByLang = votesByLang map { case (lang, counts) => val countsOnly = counts map { case (_, count) => count } (lang, countsOnly.sum) } val orderedVotes = sumByLang.toSeq .sortBy { case (_, count) => count } .reverse
代码也同样简洁,但更清晰的表达了转换的发生(通过命名中间值),和正在操作的数据的结构(通过命名参数)。如果你担心这种风格污染了命名空间,用大括号{}来将表达式分组:
val orderedVotes = { val votesByLang = ... ... }