我的Lambda的学习笔记
前述
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和管道
我们对应上面的代码,可以看出,聚合操作分为三步
- 生成
- 操作、变换(可以多次)
- 消耗(只有一次)
当然我们还要知道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的学习笔记的更多相关文章
- C# Lambda表达式学习笔记
本笔记摘抄自:https://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html,记录一下学习过程以备后续查用. 一.Lambda ...
- java lambda表达式学习笔记
lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了.在java中lambda表达式是'->',在C#中是‘=>’. 杜甫说:射 ...
- lambda 表达式学习笔记
在Java中传递一个代码段并不容易,不能直接传递代码段.Java是一个面向对象语言,所以必须构造一个对象,这个对象的类需要一个方法能包含所需的代码.lambda的出现有效的解决这个问题,让代码变得更加 ...
- python函数和lambda表达式学习笔记
1. python函数 不同于其他语言,python支持函数返回多个值 为函数提供说明文档:help(函数名)或者函数名.__doc__ def str_max(str1, str2): ''' 比较 ...
- Lambda表达式学习笔记
Lambda基础语法 Java8中引入了一个新的操作符" -> ",该操作符被称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两部分: 左侧:Lamb ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lambda表达式
引言: 最初学习c#时,感觉委托.事件这块很难,其中在学习的过程中还写了一篇学习笔记:委托.事件学习笔记.今天重新温故委托.事件,并且把最近学习到和委托相关的匿名方法.Lambda表达式及泛型委托记录 ...
- Java8学习笔记----Lambda表达式 (转)
Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家 本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...
- Python学习笔记010——匿名函数lambda
1 语法 my_lambda = lambda arg1, arg2 : arg1 + arg2 + 1 arg1.arg2:参数 arg1 + arg2 + 1 :表达式 2 描述 匿名函数不需要r ...
随机推荐
- win8系统下,python 2.7安装xlrd,xlutils和xlwt的方法
一.先到python的官网上下载压缩包 二.将压缩包解压 三.将打开cmd,进入到解压文件所在的位置 四.键入 python setup.py install
- redis 设置
设置成服务命令,redis目录下,执行cmd命令 redis-server --service-install redis.windows-service.conf --loglevel verbos ...
- ubuntu 16.04安装smatrgitHG工具
SmartGit/HG 是一款开放源代码的.跨平台的.支持 Git 和 Mercurial 的 SVN 图形客户端,可运行在Windows.Linux 和 MAC OS X 系统上. 1.安装 Ubu ...
- Centos7搭建hadoop完全分布式
虽然说是完全分布式,但三个节点也都是在一台机器上.拿来练手也只能这样咯,将就下.效果是一样滴.这个我自己都忘了步骤,一起来回顾下吧. 必备知识: Linux基本命令 vim基本命令 准备软件: VMw ...
- Yii 1.1 请求报400错误
Yii的action可以带参数,比如: class PostController extends CController { public function actionCreate($categor ...
- ORACLE 快速启动监听及相关服务程序
windows7 系统下,鼠标移至任务栏右键启动任务管理器->选择服务->点击右下角服务选项 ->选中名称,键盘输入O(大写),快速找到ORACLE相关服务进程 ->将所有的O ...
- latex中长公式换行,很好的办法
今天在编辑公式时,有一个公式很长,写到一行就出去了.当时之前换行都是方程组或者在括号完之后换,都没有问题.但是今天我也换行的是在括号中间断开.这样出现问题,编辑的时候会出错误提醒.上网查了一些论坛,也 ...
- 一支烟的时间导致他错失女神,Python查看撤回消息,力挽狂澜!
2011年1月21日 微信(WeChat) 是腾讯公司于2011年1月21日推出的一个为智能终端提供即时通讯服务的免费应用程序,由张小龙所带领的腾讯广州研发中心产品团队打造 .在互联网飞速发展的下.民 ...
- kv.go
package clientv3 import ( pb "github.com/coreos/etcd/etcdserver/etcdserverpb" //protob ...
- 【bzoj 3306】树
Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Input 第一行两个整数 n, Q ,分别表示树的大小和操作数. ...