Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

我的Lambda的学习笔记

JYRoy 2019-02-12 15:20:00 阅读数:214 评论数:0 点赞数:0 收藏数:0

前述

Lambda表达式是 Java 8 的新特性。许多语言都有 Lambda 的特性。

因此使用的 Java 环境一定要 8 以上的环境。

 

Lambda

到底什么是 Lambda 表达式呢?

Lambda 表达式,也可称为闭包。Lambda 允许把函数作为一个方法的参数直接传递到方法中去。可以让我们不用费神去给函数起名。但是 Lambda 也只适合于简单的函数,对于复杂的函数,写成 Lambda 的形式反而会让人更加看不懂。

 

实例

接下来用一个实例慢慢导入 Lambda,要完成的是一个判断Person的id是否大于90的功能

首先创建一个Person类,包含 id 属性1 packageperson;2 3 /// 4 / Person类5 /@authorjyroy6 /7 // 8 public classPerson {9 @SuppressWarnings("unused")10 public intid;11 12 publicPerson() {13 14 }15 16 public Person(intid) {17 this.id =id;18 }19 20 @Override21 publicString toString() {22 return "Person [id=" + id + "]";23 }24 25 }

 

普通方法

用普通方法,在 for 循环中通过 if 进行条件判断 if(person.id>90) 1 packagenormal;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 public classTestLambda {11 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})12 public static voidmain(String[] args) {13 Random r = new Random(); //随机生成100个数 14 List lists = new ArrayList();15 for(int i=0;i<100;i++) {16 lists.add(new Person(r.nextInt(100)));17 }18 //使用 Lambda 筛选出大于90的数据 19 judge(lists);20 21 }22 @SuppressWarnings("rawtypes")23 private static void judge(Listlists) {24 for(Person person:lists) {25 if(person.id>90) { //判断是否大于90 26 System.out.println(person);27 }28 }29 }30 }

结果

 

匿名类方法

创建一个匿名类,通过匿名类来实现这个判断 id 大于90的功能。

首先提供匿名类需要的接口,用于创建一个判断的类1 packageanonymity;2 3 importperson.Person;4 5 public interfacePersonCheck {6 public booleantest(Person person);7 }

通过匿名类实现接口

1 //使用 匿名类的方式 筛选出大于90的数据 2 PersonCheck personCheck = newPersonCheck() {3 @Override4 public booleantest(Person person) {5 return person.id>90;6 }7 };

实现之后,就可以在judge函数中调用personCheck实例的test函数进行处理

1 packageanonymity;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 /// 11 / 匿名类方式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})17 public static voidmain(String[] args) {18 Random r = newRandom();19 List lists = new ArrayList();20 for(int i=0;i<100;i++) {21 lists.add(new Person(r.nextInt(100)));22 }23 24 //使用 匿名类的方式 筛选出大于90的数据 25 PersonCheck personCheck = newPersonCheck() {26 @Override27 public booleantest(Person person) {28 return person.id>90;29 }30 };31 32 judge(lists, personCheck);33 34 }35 @SuppressWarnings("rawtypes")36 private static void judge(Listlists, PersonCheck personCheck) {37 for(Person person:lists) {38 if(personCheck.test(person)) {39 System.out.println(person);40 }41 }42 }43 }

结果

 

Lambda方式

接下来就是Lambda方式了

先上 Lambda表达式的写法,运行过程序之后再做总结1 person->person.id>90

这便是一个Lambda表达式的形式,先记住这个形式,这个形式就是判断 person.id>90。

1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List lists = new ArrayList();21 for(int i=0;i<100;i++) {22 lists.add(new Person(r.nextInt(100)));23 }24 //使用 Lambda 筛选出大于90的数据 25 filter(lists, person -> person.id > 90);26 27 }28 @SuppressWarnings("rawtypes")29 private static void filter(Listlists, PersonCheck personCheck) {30 for(Person person:lists) {31 if(personCheck.test(person)) {32 System.out.println(person);33 }34 }35 }36 }

结果

实现了同样的效果

总结

上面的程序中使用了 Lambda表达式,完成了判断的功能,而且相比匿名类的写法要简单非常多,使用 Lambda 表达式可以使代码变的更加简洁紧凑。

  Lambda 表达式的语法格式:1 (parameters) ->expression2 或3 (parameters) ->{ statements; }

以下是lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

简单的例子1 //1. 不需要参数,返回值为 5 2 () -> 5 3 4 //2. 接收一个参数(数字类型),返回其2倍的值 5 x -> 2 /*x6 7 //3. 接受2个参数(数字),并返回他们的差值 8 (x, y) ->x – y9 10 //4. 接收2个int型整数,返回他们的和 11 (int x, int y) -> x +y12 13 //5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) 14 (String s) -> System.out.print(s)

 

  现在就可以解释上面的实例中的 Lambda表达式 的含义person->person.id>90即接收一个person参数,并返回大于person.id>90的数据

 

Lambda方法引用

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

可以看作是lambda的一种快捷写法,显式的指定方法的名称更具可读性。格式:目标引用+分隔符::+方法,例如,Dog::getAge就是引用了Dog类中定义的方法getAge。

注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。

 

Lambda方法引用包含一下四种:

  • 静态方法引用
  • 对象方法引用
  • 类成员方法引用
  • 构造方法引用

 

静态方法引用

首先需要有一个静态方法1 public static booleantest(Person person) {2 return person.id>90 && person.id<95;3 }

在Lambda表达式中调用这个静态方法,因为是静态方法可以不用创建对象,所以直接用类名进行调用

1 judge(lists, person -> TestLambda.test(person));

利用方法引用调用静态方法的形式

1 judge(lists, TestLambda::test);

主程序为

1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List lists = new ArrayList();21 for(int i=0;i<100;i++) {22 lists.add(new Person(r.nextInt(100)));23 }24 //使用 Lambda 筛选出大于90的数据 25 judge(lists, person -> person.id < 10);26 27 //在Lambda表达式中使用静态方法 28 judge(lists, person ->TestLambda.test(person));29 30 //直接使用静态方法 31 judge(lists, TestLambda::test);32 33 }34 35 public static booleantest(Person person) {36 return person.id>90 && person.id<95;37 }38 39 @SuppressWarnings("rawtypes")40 private static void judge(Listlists, PersonCheck personCheck) {41 for(Person person:lists) {42 if(personCheck.test(person)) {43 System.out.println(person);44 }45 }46 }47 }

 

对象方法引用

和静态方法相似,,但是在传递方法的时候,因为不是静态方法,所以必须要利用对象进行传送1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List lists = new ArrayList();21 for(int i=0;i<100;i++) {22 lists.add(new Person(r.nextInt(100)));23 }24 25 //使用引用对象方法 26 TestLambda testLambda = newTestLambda();27 judge(lists, testLambda::test2);28 29 }30 31 public booleantest2(Person person) {32 return person.id>90 && person.id<95;33 }34 35 @SuppressWarnings("rawtypes")36 private static void judge(Listlists, PersonCheck personCheck) {37 for(Person person:lists) {38 if(personCheck.test(person)) {39 System.out.println(person);40 }41 }42 }43 }

 

类成员方法引用

Person类要添加一个成员方法,才能够进行成员方法的引用1 public booleantest3() {2 return this.id>90 && this.id<95;3 }

在Lambda表达式中使用 test3方法

1 judge(lists, person -> person.test3());

利用方法引用的写法为

1 judge(lists, Person::test3);

主程序为

1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List lists = new ArrayList();21 for(int i=0;i<100;i++) {22 lists.add(new Person(r.nextInt(100)));23 }24 25 26 //使用类成员方法 27 judge(lists, person ->person.test3());28 29 //可改写为 30 judge(lists, Person::test3);31 32 33 }34 35 public static booleantest(Person person) {36 return person.id>90 && person.id<95;37 }38 39 public booleantest2(Person person) {40 return person.id>90 && person.id<95;41 }42 43 @SuppressWarnings("rawtypes")44 private static void judge(Listlists, PersonCheck personCheck) {45 for(Person person:lists) {46 if(personCheck.test(person)) {47 System.out.println(person);48 }49 }50 }51 }

 

构造方法引用

需要有返回一个对象的方法

构造方法引用形式为1 ArrayList::new 2 Person::new

 

1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.function.Supplier;6 7 public classTestLambda {8 public static voidmain(String[] args) {9 Supplier s = new Supplier() {10 publicList get() {11 return newArrayList();12 }13 };14 //引用构造器 15 List list3 = getList(ArrayList::new);16 17 }18 19 public static List getList(Suppliers){20 returns.get();21 }

 

 聚合操作

引入实例

在上面的程序中,遍历输出数据利用的是for循环的方式1 for(Person person:lists) {2 if(personCheck.test(person)) {3 System.out.println(person);4 }5 }

我们可以利用聚合操作来进行数据的输出

1 lists2 .stream()3 .filter(person -> person.id>95)4 .forEach(person -> System.out.println(person.id));

主程序为

1 packagenormal;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 public classTestLambda {11 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})12 public static voidmain(String[] args) {13 Random r = newRandom();14 List lists = new ArrayList();15 for(int i=0;i<100;i++) {16 lists.add(new Person(r.nextInt(100)));17 }18 System.out.println("使用传统方式----");19 for(Person person:lists) {20 if(person.id>90) {21 System.out.println(person);22 }23 }24 System.out.println("聚合操作方式");25 lists26 .stream()27 .filter(person -> person.id>95)28 .forEach(person ->System.out.println(person.id));29 }30 }

结果

Stream和管道

我们对应上面的代码,可以看出,聚合操作分为三步

  1. 生成
  2. 操作、变换(可以多次)
  3. 消耗(只有一次)

当然我们还要知道stream和管道的概念

Stream:Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到,前面处理的结果。注意:这个Stream和I/O中的InputStream,OutputStream是不一样的概念。

管道:指的是一系列的聚合操作。

管道又分3个部分:管道源、中间操作、结束操作

管道源:在这个例子里,源是一个List,可以用 .stream() 方法切换成管道源。但是数组没有stream() 方法,需要用 Arrays.stream(hs) 或者 Stream.of(hs)1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.Arrays;5 importjava.util.HashMap;6 importjava.util.List;7 importjava.util.Random;8 9 importcharactor.Hero;10 11 public classTestAggregate {12 13 public static voidmain(String[] args) {14 Random r = newRandom();15 List heros = new ArrayList();16 for (int i = 0; i < 5; i++) {17 heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));18 }19 //管道源是集合 20 heros21 .stream()22 .forEach(h->System.out.println(h.name));23 24 //管道源是数组 25 Hero hs[] = heros.toArray(newHero[heros.size()]);26 Arrays.stream(hs)27 .forEach(h->System.out.println(h.name));28 29 }30 }

 

中间操作: 每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。中间操作比较多,主要分两类对元素进行筛选 和 转换为其他形式的流

对元素进行筛选:filter 匹配distinct 去除重复(根据equals判断)sorted 自然排序sorted(Comparator) 指定排序limit 保留skip 忽略    转换为其他形式的流mapToDouble 转换为double的流map 转换为任意类型的流1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importcharactor.Hero;8 9 public classTestAggregate {10 11 public static voidmain(String[] args) {12 Random r = newRandom();13 List heros = new ArrayList();14 for (int i = 0; i < 5; i++) {15 heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));16 }17 //制造一个重复数据 18 heros.add(heros.get(0));19 System.out.println("初始化集合后的数据 (最后一个数据重复):");20 System.out.println(heros);21 System.out.println("满足条件hp>100&&damage<50的数据");22 23 heros24 .stream()25 .filter(h->h.hp>100&&h.damage<50)26 .forEach(h->System.out.print(h));27 28 System.out.println("去除重复的数据,去除标准是看equals");29 heros30 .stream()31 .distinct()32 .forEach(h->System.out.print(h));33 System.out.println("按照血量排序");34 heros35 .stream()36 .sorted((h1,h2)->h1.hp>=h2.hp?1:-1)37 .forEach(h->System.out.print(h));38 39 System.out.println("保留3个");40 heros41 .stream()42 .limit(3)43 .forEach(h->System.out.print(h));44 45 System.out.println("忽略前3个");46 heros47 .stream()48 .skip(3)49 .forEach(h->System.out.print(h));50 51 System.out.println("转换为double的Stream");52 heros53 .stream()54 .mapToDouble(Hero::getHp)55 .forEach(h->System.out.println(h));56 57 System.out.println("转换任意类型的Stream");58 heros59 .stream()60 .map((h)-> h.name + " - " + h.hp + " - " +h.damage)61 .forEach(h->System.out.println(h));62 63 }64 }

 

结束操作:当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回, 结束操作才进行真正的遍历行为,在遍历的时候,才会去进行中间操作的相关判断.

常见结束操作如下:forEach() 遍历每个元素toArray() 转换为数组min(Comparator) 取最小的元素max(Comparator) 取最大的元素count() 总数findFirst() 第一个元素1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.Arrays;5 importjava.util.List;6 importjava.util.Random;7 8 importorg.omg.Messaging.SYNCWITHTRANSPORT;9 10 importcharactor.Hero;11 12 public classTestAggregate {13 14 public static voidmain(String[] args) {15 Random r = newRandom();16 List heros = new ArrayList();17 for (int i = 0; i < 5; i++) {18 heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));19 }20 System.out.println("遍历集合中的每个数据");21 heros22 .stream()23 .forEach(h->System.out.print(h));24 System.out.println("返回一个数组");25 Object[] hs=heros26 .stream()27 .toArray();28 System.out.println(Arrays.toString(hs));29 System.out.println("返回伤害最低的那个英雄");30 Hero minDamageHero = 31 heros32 .stream()33 .min((h1,h2)->h1.damage-h2.damage)34 .get();35 System.out.print(minDamageHero);36 System.out.println("返回伤害最高的那个英雄");37 38 Hero mxnDamageHero = 39 heros40 .stream()41 .max((h1,h2)->h1.damage-h2.damage)42 .get();43 System.out.print(mxnDamageHero);44 45 System.out.println("流中数据的总数");46 long count =heros47 .stream()48 .count();49 System.out.println(count);50 51 System.out.println("第一个英雄");52 Hero firstHero = 53 heros54 .stream()55 .findFirst()56 .get();57 58 System.out.println(firstHero);59 60 }61 }

 

编程实例

首选准备100个Person对象,id都是随机数。分别用传统方式和聚合操作的方式,把id第三高的名称和id打印出来

Person.java1 packageaggregation;2 3 public classPerson {4 publicString name;5 public intid;6 7 public Person(String name, intid){8 this.name =name;9 this.id =id;10 }11 12 @Override13 publicString toString() {14 return "Person [name=" + name + ", id=" + id + "]";15 }16 }

TestLambda.java

1 packageaggregation;2 3 importjava.util.ArrayList;4 importjava.util.Collections;5 importjava.util.Comparator;6 importjava.util.List;7 importjava.util.Random;8 9 importlambda.Check;10 11 public classTestLambda {12 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})13 public static voidmain(String[] args) {14 Random r = newRandom();15 List lists = new ArrayList();16 for(int i=0;i<100;i++) {17 lists.add(new Person("Person"+i, r.nextInt(100)));18 }19 System.out.println("使用传统方式----");20 Comparator c = new Comparator() {21 @Override22 public intcompare(Person p1, Person p2) {23 return p1.id >= p2.id ? 1 : -1;24 }25 };26 Collections.sort(lists, c);27 System.out.println(lists.get(2));28 29 System.out.println("聚合操作方式----");30 Person p =lists31 .stream()32 .sorted((person1, person2) -> person1.id>=person2.id?1:-1)33 .skip(2)34 .findFirst()35 .get();36 System.out.println(p);37 }38 }

结果

 

 

 

版权声明
本文为[JYRoy]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/jyroy/p/10363536.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领