jdk8中的lambda表达式
来源:互联网 发布:卡通睡衣品牌知乎 编辑:程序博客网 时间:2024/05/16 01:54
什么是lambda表达式?
lambda表达式又称闭包,允许将一个函数当作方法的参数来传递(传递函数)或者说把代码当作数据来传递。
长啥样?
如下两个示例,示例1为非lambda表达式实现的形态(多行代码),示例2为使用lambda表示式后的样子(1行代码)。
功能:实现一个过滤符合指定条件的人群
示例1:
interface CheckPerson { //步骤1.定义接 boolean test(Person p); }class CheckPersonEligibleForSelectiveService implements CheckPerson {//步骤2. 实现类public boolean test(Person p) { return p.gender == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25;}}printPersons(roster, new CheckPersonEligibleForSelectiveService());//步骤3.调用
示例2:
printPersons(roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25);
为啥要用lambda表达式?
如上示例,显然使用lambda表示式的形式更加简洁,漂亮。当然,lambda表达式带来的好处远不如此,其在并发编程中带来的优势更是不言而喻。
拿个官方栗子来看看
打印年龄大于指定值的成员信息
public static void printPersonsOlderThan(List<Person> roster, int age) { for (Person p : roster) { if (p.getAge() >= age) { p.printPerson(); } }}
上述示例会随着功能或者数据结构类型(int 变更为 double)的改变显得稳定性较差
如需求为年龄在指定范围内,则实现方法为:public static void printPersonsWithinAgeRange( List<Person> roster, int low, int high) { for (Person p : roster) { if (low <= p.getAge() && p.getAge() < high) { p.printPerson(); } }}
为支持多样的需求,对过滤条件做抽象,如下
public static void printPersons( List<Person> roster, CheckPerson tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); } }}
为支持上述设计做如下实现:见示例1。(接口,本地实现类,调用) 对示例1使用匿名类做简化(省去本地实现类CheckPersonEligibleForSelectiveService)后,代码如下:
printPersons(roster, new CheckPerson() { public boolean test(Person p) { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; }});
如此代码简化为 接口+匿名类调用
3. 使用lambda表达式做简化 由于CheckPerson接口为函数接口(仅有一个抽象类),可以对使用lambda表示式代替匿名函数
printPersons( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25);
4.继续简化。使用标准函数接口
interface CheckPerson { boolean test(Person p);}
对于此类函数接口(含有一个入参和boolean返回值),表现实现相对简单。由于此类接口过于简单,以至于没有必要在自己的应用中定义,所以jdk8在java.util.function包提供了几个标准的函数接口以方便用户使用。
对于此例接口(含有一个入参和boolean返回值)可以使用Predicate
interface Predicate<T> { boolean test(T t);}
由此,该例本地实现类可变为
public static void printPersonsWithPredicate( List<Person> roster, Predicate<Person> tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); } }}
5.尽可能多的使用lambda表达式
public static void printPersonsWithPredicate( List<Person> roster, Predicate<Person> tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); } }}
如上所示,该功能为对符合条件的对象做动作(打印p.printPerson),如果需求变更为仅打印名称或仅打印email呢?是不是要重新在写相应的代码逻辑呢?代码就这样膨胀了。
然而使用lambda表达式可以在调用时指定具体的动作,无需写冗长的匿名类。如此使用lambda表达式来来实现动作的描述
对于p.printPerson()此类方法--需要一个参数Person对像且无返回值,可使用标准函数接口Consumer(抽象方法为accept)代替,如此待接口定义做进一步优化
public static void processPersons( List<Person> roster, Predicate<Person> tester, Consumer<Person> block) { for (Person p : roster) { if (tester.test(p)) { block.accept(p); } }}
实例调用,此时完成将 printPerson的动作转换为lambda表示式的形式
processPersons( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25, p -> p.printPerson());
此过程中操作对象为person, 如果想操作其中的成员变量呢,我们需要通过对象获取该对象的成员变量,即需要一个函数接口支持一个入参和返回。标准函数接口中Function可以支持,抽象方法为apply, 如此我们可以使用该接口,实现map映射(通过person获取对应成员变量),函数定义如下:
public static void processPersonsWithFunction( List<Person> roster, Predicate<Person> tester, Function<Person, String> mapper, Consumer<String> block) { for (Person p : roster) { if (tester.test(p)) { String data = mapper.apply(p); block.accept(data); } }}
实例调用
processPersonsWithFunction( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25, p -> p.getEmailAddress(), email -> System.out.println(email));
6.使用泛型 使用泛型重新定义processPersonsWithFunction
public static <X, Y> void processElements( Iterable<X> source, Predicate<X> tester, Function <X, Y> mapper, Consumer<Y> block) { for (X p : source) { if (tester.test(p)) { Y data = mapper.apply(p); block.accept(data); } }}
实例调用
processElements( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25, p -> p.getEmailAddress(), email -> System.out.println(email));
如上调用依次做如下操作:
1)从集合roster依次取出元素
2)做条件过滤
3)做map影射,由对象获取成员变量
4)做动作,打印成员变量
如上使用到的几个标准函数接口如下
7.将lambda表达式做为参数做聚合操作
如下为对符合指定条件的人群打印其emalAddress
roster .stream() .filter( p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25) .map(p -> p.getEmailAddress()) .forEach(email -> System.out.println(email));
其中各聚合操作对应的意义如下
总体说来,lambda表达式在简化代码的同时,使应用对易变的需求有更好的适应性,同时并发操作使其可更好的利用硬件资源。
- jdk8中的lambda表达式
- JDK8 lambda表达式
- JDK8 Lambda表达式教程
- JDK8-Lambda表达式(一)
- JDK8 ——lambda表达式
- jdk8使用lambda表达式排序
- jdk8新特性->lambda表达式
- JDK8新特性之Lambda表达式
- Jdk8之lambda表达式的使用(一)
- Jdk8之lambda表达式的使用(二)
- JDK8新特性之Lambda表达式
- jdk8新特性 lambda表达式详解
- jdk8新特性之lambda表达式
- Jdk8之lambda表达式的使用(一)
- Jdk8之lambda表达式的使用(二)
- JDK8中Lambda表达式的使用
- JDK8新特性之Lambda表达式
- JDK8新特性之Lambda表达式
- Java语言基础 数组的排序算法
- 动态规划 HDU-2577
- HDU - 5999 The Third Cup is Free 贪心
- SpringMVC的Controller返回各种视图
- 【LeetCode】 143. Reorder List
- jdk8中的lambda表达式
- Java语言基础 数组的二分查找法
- 值得信任的邀约--记我的阿里云
- python 爬虫 一键爬取 淘宝天猫宝贝页面主图颜色图和详情图
- 【PAT】1086. Tree Traversals Again
- 第十一章:用core.async掌握并发过程
- 基于JAVA的ARP欺骗的程序实现
- C++引用和指针区别
- 枚举法(穷举法)