Java 中的 Lambda 表达式
Java 中的 Lambda 表达式
本文连接:https://code.csdn.net/liuche911/lambdainjava/file/LambdainJava.md
本文翻译自Oracle官方Java教程 "The Java(TM) Tutorials" 中的Lambda表达式一节。我从新写了代码,所以可能跟原文不大一样。
另外就是我没有搜索是否有人已经翻译过这段教程,同时我相信网上关于Lambda表达式的帖子多如牛毛。。。本文作为自我总结的意义显然高于传播技术 :)
先看一个例子
假设我们有一个 Person
类,大致如下:
```Java
public class Person {
private String name;
private int age;
public static enum Sex {
MALE, FEMALE
};
private Sex sex;
private double height;
private double weight;
public Person(String name, int age, Sex sex, double height, double weight) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.weight = weight;
}
@Override
public String toString() {
return String.format("%s Age:%d, Sex:%s%n", name, age,
sex == Sex.MALE ? "male" : "female");
}
//省略了set&get方法
}
```
再来一个 PersonList
类存放一组人,大致如下
```Java
public class PersonList {
private List<Person> persons;
public PersonList(List<Person> persons) {
super();
this.persons = persons;
}
public boolean addPerson(Person person) {
return this.persons.add(person);
}
public boolean removePerson(Person person) {
return this.persons.remove(person);
}
}
```
在给个简单的测试函数吧,假设就在 main
函数里实现:
```Java
public static void main(String[] args) {
PersonList personList = new PersonList(new ArrayList<Person>());
personList.addPerson(new Person("老王", 88, Person.Sex.MALE, 1.7, 60));
personList.addPerson(new Person("小丽", 12, Person.Sex.FEMALE, 1.60, 40));
personList.addPerson(new Person("小白", 19, Person.Sex.MALE, 1.78, 66));
personList.addPerson(new Person("小美", 22, Person.Sex.FEMALE, 1.7, 50));
}
```
现在我们需要编写一个函数,找出这一组人里,年纪小于等于(比方说)50岁的人,该怎么办呢?
普通青年的做法
```Java
/**
* 普通青年 返回年纪小于age的人
*
* @param age
* 小于该年龄
*/
public void printPersonAgeYoungerThan(int age) {
for (Person p : persons) {
if (p.getAge() <= age) {
System.out.println(p.toString());
}
}
}
```
这样做固然是满足需求,而且还没有“二逼”到 if (p.getAge() <= 50)
的地步,些许还有点灵活性;但是如果用户还想查询年纪大于50的人呢?再写一个函数?那么查询年纪大于18又小于50的人呢?且看文艺青年是怎么做的:
文艺青年的做法
```Java
/**
* 文艺青年 返回年纪大于等于low,小于等于high的人
*
* @param low
* @param high
*/
public void printPersonAgeIn(int low, int high) {
for (Person p : persons) {
if (p.getAge() >= low && p.getAge() <= high) {
System.out.println(p.toString());
}
}
}
```
这下似乎好多了,“小于等于50岁”可以理解为“大于等于-100岁,小于等于50岁”。大于多少岁的时候,上界即使不放心,那就飚到10000岁!再不放心就 Integer.MAX_VALUE
,内心终于得到平静……
不过呀,用户可能还没完,他说不定想查询“满足美国服义务兵役条件的人~”,即“年龄在18到25岁的男性”。嘿嘿,烦了吧,还好我们有更厉害的程序猿青年!
程序猿青年的做法
```Java
public static interface CheckPersons {
boolean test(Person p);
}
/**
* 程序猿:返回满足CheckPersons tester的test方法的人
*
* @param tester
*/
public void printPersonAccordinTester(CheckPersons tester) {
for (Person p : persons) {
if (tester.test(p)) {
System.out.println(p.toString());
}
}
}
```
你再看~作为API提供者,我不干啦,接口甩出来,调用放好,从此放权给用户,想查询什么条件,自己写吧,我都能满足你。那么作为客户,可以考虑使用静态类实现CheckPerson接口方便经常调用,也可以图方便使用匿名类:
```Java
personList.printPersonAccordinTester(new PersonList.CheckPersons() {
@Override
public boolean test(Person p) {
return p.getSex() == Person.Sex.MALE && p.getAge() >= 18
&& p.getAge() <= 25;
}
});
```
Wo!看来我们找到了问题的通解,但是,我们还没有提到Lambda表达式吧?这不是本文的重点么?
在Eclipse中使用Lambda表达式
首先要声明的是Lambda表达式是Java8的新特性之一,如果你发现下文的代码无法编译,其实只是因为你没有安装最新的JDK罢了,下载连接
另外你还需要使Eclipse支持Java8,只需这样:官方教程
这样做之后,可能因为JRE为设为jre8所以无法编译,见下图:
如果原来使用的是jre7的话,需要选择 Edit
,选择Alternate JRE:
,再选择 Installed JREs...
,再选择jre8的安装目录就可以自动识别出来。
使用Lambda表达式
Lambda表达式最适合的地方大概就是实现只有一个抽象函数的接口。且看:
```Java
personList.printPersonAccordinTester(p -> p.getSex()==Person.Sex.MALE &&
p.getAge()>=18 && p.getAge()<=25 );
```
是不是很清晰? Lambda表达式的语法很简单变量声明(忽略类型)
+表达式
。当变量多于一个时,用 (v1,v2)
表示,表达式多于一行时用{e1; e2; e3; return e4;}
表示。
需要注意的是,当使用大括号后,括号内的全部内容就相当于替代了接口函数的全部内容,所以必要的 return
就不能省略了。
一个小优化
像我们的例子里定义的这个接口——输入参数,返回boolean——其实非常常用,Java在java.util.function中定义了一簇类似的函数,它们使用了泛型,足够我们使用了,这样就不必自己定义接口了。
注意这依然是Java8的新特性
于是乎 printPersonAccordinTester()
可以改写成这样: Java public void printPersonAccordinTester(Predicate<Person> tester) { for (Person p : persons) { if (tester.test(p)) { System.out.println(p.toString()); } } }
让Lambda无处不在
让我们把 print
方法更加定制化一些,不光能自定义选择,还可以自定义查询的内容,以及查询后做什么:
```Java
public void dealTheList(Predicate<Person> tester,
Function<Person, String> mapper, Consumer<String> dealer) {
for (Person p : persons) {
if (tester.test(p)) {
String s = mapper.apply(p);
dealer.accept(s);
}
}
}
```
几乎就是一个 Select FROM WHERE
结构呀,那再看调用:
```Java
personList.dealTheList(p -> p.getSex() == Person.Sex.FEMALE,
p -> String.valueOf(p.getHeight()), s -> System.out.println(s));
```
条件:女性,查询:身高,处理:打印;
有没有启发性??
Java还支持stream(),专门提供一种串行的,更优雅的处理手段:
```Java
personList.getPersons().stream()
.filter(p -> p.getSex() == Person.Sex.FEMALE)
.map(p -> p.getHeight()).forEach(h -> System.out.println(h));
```
关于聚合运算,还可以参考Aggregate Operations
小节
总而言之,在只需要单个函数,特别是这个函数还只需一句话就搞定的时候,使用Lambda表达式可以极大的简化繁琐的定义,使代码更清晰、更侧重逻辑而非结构。
算是一种编译型语言融合解释型语言有点的一种技巧吧。
谢谢阅读。
posted on 2014-04-25 15:32 Robert Liu 阅读(261) 评论(0) 编辑 收藏 举报