前述

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

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

Lambda

  到底什么是 Lambda 表达式呢?

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

实例

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

  首先创建一个Person类,包含 id 属性

 package person;

 /**
* Person类
* @author jyroy
*
*/
public class Person {
@SuppressWarnings("unused")
public int id; public Person() { } public Person(int id) {
this.id = id;
} @Override
public String toString() {
return "Person [id=" + id + "]";
} }

普通方法

  用普通方法,在 for 循环中通过 if 进行条件判断 if(person.id>90)

 package normal;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import lambda.Check;
import person.Person; public class TestLambda {
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random(); //随机生成100个数
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
}
//使用 Lambda 筛选出大于90的数据
judge(lists); }
@SuppressWarnings("rawtypes")
private static void judge(List<Person> lists) {
for(Person person:lists) {
if(person.id>90) { //判断是否大于90
System.out.println(person);
}
}
}
}

  结果

匿名类方法

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

  首先提供匿名类需要的接口,用于创建一个判断的类

 package anonymity;

 import person.Person;

 public interface PersonCheck {
public boolean test(Person person);
}

  通过匿名类实现接口

 //使用 匿名类的方式 筛选出大于90的数据
PersonCheck personCheck = new PersonCheck() {
@Override
public boolean test(Person person) {
return person.id>90;
}
};

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

 package anonymity;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import lambda.Check;
import person.Person; /**
* 匿名类方式
* @author jyroy
*
*/
public class TestLambda {
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
} //使用 匿名类的方式 筛选出大于90的数据
PersonCheck personCheck = new PersonCheck() {
@Override
public boolean test(Person person) {
return person.id>90;
}
}; judge(lists, personCheck); }
@SuppressWarnings("rawtypes")
private static void judge(List<Person> lists, PersonCheck personCheck) {
for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}
}
}

  结果

Lambda方式

  接下来就是Lambda方式了

  先上 Lambda表达式的写法,运行过程序之后再做总结

 person->person.id>90

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

 package lambda;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import anonymity.PersonCheck;
import person.Person; /**
* Lambda表达式
* @author jyroy
*
*/
public class TestLambda { @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
}
//使用 Lambda 筛选出大于90的数据
filter(lists, person -> person.id > 90); }
@SuppressWarnings("rawtypes")
private static void filter(List<Person> lists, PersonCheck personCheck) {
for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}
}
}

  结果 

  实现了同样的效果

总结

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

  Lambda 表达式的语法格式:

 (parameters) -> expression

(parameters) ->{ statements; }

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

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

简单的例子

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

  现在就可以解释上面的实例中的 Lambda表达式 的含义

  person->person.id>90
 
 即接收一个person参数,并返回大于person.id>90的数据

Lambda方法引用

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

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

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

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

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

静态方法引用

  首先需要有一个静态方法

 public static boolean test(Person person) {
return person.id>90 && person.id<95;
}

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

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

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

 judge(lists, TestLambda::test);

  主程序为

 package references;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import anonymity.PersonCheck;
import person.Person; /**
* Lambda表达式
* @author jyroy
*
*/
public class TestLambda { @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
}
//使用 Lambda 筛选出大于90的数据
judge(lists, person -> person.id < 10); //在Lambda表达式中使用静态方法
judge(lists, person -> TestLambda.test(person)); //直接使用静态方法
judge(lists, TestLambda::test); } public static boolean test(Person person) {
return person.id>90 && person.id<95;
} @SuppressWarnings("rawtypes")
private static void judge(List<Person> lists, PersonCheck personCheck) {
for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}
}
}

对象方法引用

  和静态方法相似,,但是在传递方法的时候,因为不是静态方法,所以必须要利用对象进行传送

 package references;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import anonymity.PersonCheck;
import person.Person; /**
* Lambda表达式
* @author jyroy
*
*/
public class TestLambda { @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
} //使用引用对象方法
TestLambda testLambda = new TestLambda();
judge(lists, testLambda::test2); } public boolean test2(Person person) {
return person.id>90 && person.id<95;
} @SuppressWarnings("rawtypes")
private static void judge(List<Person> lists, PersonCheck personCheck) {
for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}
}
}

类成员方法引用

  Person类要添加一个成员方法,才能够进行成员方法的引用

     public boolean test3() {
return this.id>90 && this.id<95;
}

  在Lambda表达式中使用 test3方法

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

  利用方法引用的写法为

 judge(lists,  Person::test3);

  主程序为

 package references;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import anonymity.PersonCheck;
import person.Person; /**
* Lambda表达式
* @author jyroy
*
*/
public class TestLambda { @SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
} //使用类成员方法
judge(lists, person -> person.test3()); //可改写为
judge(lists, Person::test3); } public static boolean test(Person person) {
return person.id>90 && person.id<95;
} public boolean test2(Person person) {
return person.id>90 && person.id<95;
} @SuppressWarnings("rawtypes")
private static void judge(List<Person> lists, PersonCheck personCheck) {
for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}
}
}

构造方法引用

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

  构造方法引用形式为

 ArrayList::new
Person::new
 package lambda;

 import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier; public class TestLambda {
public static void main(String[] args) {
Supplier<List> s = new Supplier<List>() {
public List get() {
return new ArrayList();
}
};
//引用构造器
List list3 = getList(ArrayList::new); } public static List getList(Supplier<List> s){
return s.get();
}

聚合操作

引入实例

  在上面的程序中,遍历输出数据利用的是for循环的方式

 for(Person person:lists) {
if(personCheck.test(person)) {
System.out.println(person);
}
}

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

 lists
.stream()
.filter(person -> person.id>95)
.forEach(person -> System.out.println(person.id));

  主程序为

 package normal;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import lambda.Check;
import person.Person; public class TestLambda {
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person(r.nextInt(100)));
}
System.out.println("使用传统方式----");
for(Person person:lists) {
if(person.id>90) {
System.out.println(person);
}
}
System.out.println("聚合操作方式");
lists
.stream()
.filter(person -> person.id>95)
.forEach(person -> System.out.println(person.id));
}
}

  结果

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)

 package lambda;

 import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) {
Random r = new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
//管道源是集合
heros
.stream()
.forEach(h->System.out.println(h.name)); //管道源是数组
Hero hs[] = heros.toArray(new Hero[heros.size()]);
Arrays.stream(hs)
.forEach(h->System.out.println(h.name)); }
}

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

      对元素进行筛选:
        filter 匹配
        distinct 去除重复(根据equals判断)
        sorted 自然排序
        sorted(Comparator<T>) 指定排序
        limit 保留
        skip 忽略
         转换为其他形式的流
        mapToDouble 转换为double的流
        map 转换为任意类型的流

 package lambda;

 import java.util.ArrayList;
import java.util.List;
import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) {
Random r = new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
//制造一个重复数据
heros.add(heros.get(0));
System.out.println("初始化集合后的数据 (最后一个数据重复):");
System.out.println(heros);
System.out.println("满足条件hp>100&&damage<50的数据"); heros
.stream()
.filter(h->h.hp>100&&h.damage<50)
.forEach(h->System.out.print(h)); System.out.println("去除重复的数据,去除标准是看equals");
heros
.stream()
.distinct()
.forEach(h->System.out.print(h));
System.out.println("按照血量排序");
heros
.stream()
.sorted((h1,h2)->h1.hp>=h2.hp?1:-1)
.forEach(h->System.out.print(h)); System.out.println("保留3个");
heros
.stream()
.limit(3)
.forEach(h->System.out.print(h)); System.out.println("忽略前3个");
heros
.stream()
.skip(3)
.forEach(h->System.out.print(h)); System.out.println("转换为double的Stream");
heros
.stream()
.mapToDouble(Hero::getHp)
.forEach(h->System.out.println(h)); System.out.println("转换任意类型的Stream");
heros
.stream()
.map((h)-> h.name + " - " + h.hp + " - " + h.damage)
.forEach(h->System.out.println(h)); }
}

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

  常见结束操作如下:
    forEach() 遍历每个元素
    toArray() 转换为数组
    min(Comparator<T>) 取最小的元素
    max(Comparator<T>) 取最大的元素
    count() 总数
    findFirst() 第一个元素

 package lambda;

 import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random; import org.omg.Messaging.SYNC_WITH_TRANSPORT; import charactor.Hero; public class TestAggregate { public static void main(String[] args) {
Random r = new Random();
List<Hero> heros = new ArrayList<Hero>();
for (int i = 0; i < 5; i++) {
heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
}
System.out.println("遍历集合中的每个数据");
heros
.stream()
.forEach(h->System.out.print(h));
System.out.println("返回一个数组");
Object[] hs= heros
.stream()
.toArray();
System.out.println(Arrays.toString(hs));
System.out.println("返回伤害最低的那个英雄");
Hero minDamageHero =
heros
.stream()
.min((h1,h2)->h1.damage-h2.damage)
.get();
System.out.print(minDamageHero);
System.out.println("返回伤害最高的那个英雄"); Hero mxnDamageHero =
heros
.stream()
.max((h1,h2)->h1.damage-h2.damage)
.get();
System.out.print(mxnDamageHero); System.out.println("流中数据的总数");
long count = heros
.stream()
.count();
System.out.println(count); System.out.println("第一个英雄");
Hero firstHero =
heros
.stream()
.findFirst()
.get(); System.out.println(firstHero); }
}

编程实例

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

  Person.java

 package aggregation;

 public class Person {
public String name;
public int id; public Person(String name, int id){
this.name = name;
this.id = id;
} @Override
public String toString() {
return "Person [name=" + name + ", id=" + id + "]";
}
}

  TestLambda.java

 package aggregation;

 import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random; import lambda.Check; public class TestLambda {
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public static void main(String[] args) {
Random r = new Random();
List<Person> lists = new ArrayList<Person>();
for(int i=0;i<100;i++) {
lists.add(new Person("Person"+i, r.nextInt(100)));
}
System.out.println("使用传统方式----");
Comparator<Person> c = new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.id >= p2.id ? 1 : -1;
}
};
Collections.sort(lists, c);
System.out.println(lists.get(2)); System.out.println("聚合操作方式----");
Person p = lists
.stream()
.sorted((person1, person2) -> person1.id>=person2.id?1:-1)
.skip(2)
.findFirst()
.get();
System.out.println(p);
}
}

  结果

  

我的Lambda的学习笔记的更多相关文章

  1. C# Lambda表达式学习笔记

    本笔记摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,记录一下学习过程以备后续查用.     一.Lambda ...

  2. java lambda表达式学习笔记

    lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了.在java中lambda表达式是'->',在C#中是‘=>’. 杜甫说:射 ...

  3. lambda 表达式学习笔记

    在Java中传递一个代码段并不容易,不能直接传递代码段.Java是一个面向对象语言,所以必须构造一个对象,这个对象的类需要一个方法能包含所需的代码.lambda的出现有效的解决这个问题,让代码变得更加 ...

  4. python函数和lambda表达式学习笔记

    1. python函数 不同于其他语言,python支持函数返回多个值 为函数提供说明文档:help(函数名)或者函数名.__doc__ def str_max(str1, str2): ''' 比较 ...

  5. Lambda表达式学习笔记

    Lambda基础语法 Java8中引入了一个新的操作符" -> ",该操作符被称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两部分: 左侧:Lamb ...

  6. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  7. 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式

    引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录 ...

  8. Java8学习笔记----Lambda表达式 (转)

    Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家       本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...

  9. Python学习笔记010——匿名函数lambda

    1 语法 my_lambda = lambda arg1, arg2 : arg1 + arg2 + 1 arg1.arg2:参数 arg1 + arg2 + 1 :表达式 2 描述 匿名函数不需要r ...

随机推荐

  1. 基于Python的数据分析(2):字符串编码

    在上一篇文章<基于Python的数据分析(1):配置安装环境>中的第四个步骤中我们在python的启动步骤中强制要求加载sitecustomize.py文件并设置其默认编码为"u ...

  2. NopCommerce是什么(转自CNSD)

    NopCommerce是什么 nopCommerce--最好的免费购物车!nopCommerce是一个开源的解决方案.它是一个具有综合功能.对于新在线业务来说亦易于使用的解决方案,同时它也是一个功能强 ...

  3. 瞎捣鼓的code highlight

    int a ; int b; public int  a ;int b   char c; h2 { text-align: left;}.postTitle{ background-color:#F ...

  4. Python并发编程之线程消息通信机制任务协调(四)

    大家好,并发编程 进入第四篇. 本文目录 前言 Event事件 Condition Queue队列 总结 . 前言 前面我已经向大家介绍了,如何使用创建线程,启动线程.相信大家都会有这样一个想法,线程 ...

  5. 由清除float原理到BFC

    关于浮动 设置为浮动的元素会脱离当前文档流,向左或向右移动直到边缘遇到另一个浮动元素或者到达边界.普通元素不会对齐造成影响. 浮动是把双刃剑,在给我们的布局带来便利的同时有一些缺点需要我们去解决.例如 ...

  6. 实验效果展示(会声会影+FSCapture)

    第一步,视频录制: 利用屏幕录制软件(Eg:FSCapture,可设定矩形区域)录制信号采集过程,存储. 第二步,视频叠加制作 1)导入视频 2)主轨,复叠轨视频安插&时序调整 3)两个视频图 ...

  7. PAT1100:Mars Numbers

    1100. Mars Numbers (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue People o ...

  8. 绕过token

    网站搭好了,下一步的目标就是直奔后台.因为一般前端在未登录的情况下只有查的功能.咱们的目标是增删改. 看到有添加功能时,先别着急的直接黑盒测试.先看看有没有防护 ######## 查看源码,搜索tok ...

  9. 如何修改Tomcat默认端口?

    修改的原因: 关于8080端口:8080端口同80端口,是被用于WWW代理服务的,可以实现网页浏览,经常在访问某个网站或使用代理服务器的时候,会加上":8080"端口号.另外Apa ...

  10. fiddler抓包软件的使用--请求头--ajax

    User-Agent: FiddlerHost: localhost:49828Content-Length: 0Accept: application/xmlContent-Type: applic ...