1. lambda表达式

1.1 什么是lambda

以java为例,可以对一个java变量赋一个值,比如int a = 1,而对于一个方法,一块代码也是赋予给一个变量的,对于这块代码,或者说被赋给变量的函数,就是一个lambda表达式

//为变量赋值

int a = 1;

//将代码块赋值给变量

var = public void fun(int x){

x+1;

}

//可以简化

var = (x)->x+1;

1.2 java为什么要引入lambda

lambda是为函数式编程服务的

编程语言共性之------什么是函数式编程?

函数式编程是一种编程范式,也就是如何编写程序的方法论,主要思想是把运算过程尽量编写成一系列嵌套的函数调用,FP强调“everything is lambda",并且强调在逻辑处理中不变性的重要性

OOP强调“everything is object”,以及object之间的消息传递。通过消息传递改变每个Object的内部状态,但是很多情况代码的编写实际上是用不到对象的,比如,对一组数据做加工,先查询,然后聚合,聚合后排序,再join,再排序,再聚合,再转换(map)得到最终的结果。这个过程,用FP的函数就很自然

result = func1(func2(func3...funcN(x))))

java为了在原先oop的思想上增加函数式编程的使用,在java8上增加了lambda函数的新特性

除此之外,lambda表达式的引入还使得代码更为简洁,可以避免生成过多的污染环境的无用实现类(下面说)

1.3 如何使用lambda表达式

lambda表达式的引入可以避免生成过多的污染环境的实现类;

lambda表达式可以被赋值给一个变量,那么这个变量的类型是什么?

在java中,所有的Lambda的类型都是一个接口,而Lambda表达式本身,需要是这个接口的实现,这个接口需要具备三个特征,具备这些特征的接口叫做函数式接口

函数式接口只有一个抽象方法

default方法为默认实现,不计入抽象方法

如果接口声明了一个覆盖java.lang.Object的全局方法之一的抽象方法,那么它不会计入接口的抽象方法数量中,因为接口的任何实现都将具有java.lang.Object或其他地方的实现

如何使用lambda表达式

比如Comparator接口就是一个函数式接口,所以他可以使用lambda表达式,在之前使用comparator对一个list排序是下面这样的

List list = new ArrayList<>();

Collections.sort(list, new Comparator() {

@Override

public int compare(Integer o1, Integer o2) {

return o1-o2;

}

});

可以看到上面实际真正有用的是return o1 - o2,上面的代码使用lambda表达式写如下

Collections.sort(list, ((o1, o2) -> o1-o2));

Lambda 表达式的基础语法:Lambda 操作符->将 Lambda 表达式拆分成两部分:

左侧:Lambda 表达式的参数列表;

右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体;

语法格式一:无参数,无返回值

() -> System.out.println("Hello Lambda!");

语法格式二:有一个参数,并且无返回值

(x) -> System.out.println(x)

语法格式三:若只有一个参数,小括号可以省略不写

x -> System.out.println(x)

语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

Comparator com = (x, y) -> {

System.out.println("函数式接口");

return Integer.compare(x, y);

};

语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

Comparator com = (x, y) -> Integer.compare(x, y);

1.4 lambda表达式方法引用,构造器引用和数组引用

方法引用

若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用

对象的引用 :: 实例方法名

类名 :: 静态方法名

类名 :: 实例方法名

①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!

②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName

//对象的引用 :: 实例方法名

@Test

public void test1(){

// 之前我们是这样写的

Employee emp = new Employee(101, "张三", 18, 9999);

Supplier sup = () -> emp.getName();

System.out.println(sup.get());

System.out.println("----------------------------------");

// 现在我们是这样写的

Supplier sup2 = emp::getName;

System.out.println(sup2.get());

}

//类名 :: 静态方法名

@Test

public void test2(){

Comparator com = (x, y) -> Integer.compare(x, y);

System.out.println("-------------------------------------");

Comparator com2 = Integer::compare;

}

//类名 :: 实例方法名

@Test

public void test3(){

BiPredicate bp = (x, y) -> x.equals(y);

System.out.println(bp.test("abcde", "abcde"));

System.out.println("-----------------------------------------");

BiPredicate bp2 = String::equals;

System.out.println(bp2.test("abc", "abc"));

}

构造器引用

对于person类,有两个构造器

class Person {

String firstName;

String lastName;

Person() {}

Person(String firstName, String lastName) {

this.firstName = firstName;

this.lastName = lastName;

}

}

现在有一个工厂接口用来生成person类

// Person 工厂

interface PersonFactory

{

P create(String firstName, String lastName);

}

我们可以通过 :: 关键字来引用 Person 类的构造器,来代替手动去实现这个工厂接口:

// 直接引用 Person 构造器

PersonFactory personFactory = Person::new;

Person person = personFactory.create("Peter", "Parker");

Person::new 这段代码,能够直接引用 Person 类的构造器。然后 Java 编译器能够根据上下文选中正确的构造器去实现 PersonFactory.create 方法

2.1 什么是Stream

Java 8引入了全新的Stream API,这里的Stream和I/O流不同,Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作,Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性

Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返

List myList =

Arrays.asList("a1", "a2", "b1", "c2", "c1");

myList

.stream() // 创建流

.filter(s -> s.startsWith("c")) // 执行过滤,过滤出以 c 为前缀的字符串

.map(String::toUpperCase) // 转换成大写

.sorted() // 排序

.forEach(System.out::println); // for 循环打印

①:中间操作会再次返回一个流,所以,我们可以链接多个中间操作,注意这里是不用加分号的。上图中的filter 过滤,map 对象转换,sorted 排序,就属于中间操作。

②:终端操作是对流操作的一个结束动作,一般返回 void 或者一个非流的结果。上图中的 forEach循环 就是一个终止操作

上面是Stream的简单实用,可以看出它也是函数式编程,更多的表达了业务逻辑

2.2 常用api

创建Stream

1. Arrays.stream()

当在日常编程中面对的是一个数组,可以使用Arrays.stream()方法来使用Stream

Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};

long count = Arrays.stream(array).filter(i->i>20).count();

2. Stream.of()

当面对数组时除了可以使用Arrays.stream()方法外,还可以使用Stream将需要的数组转成Stream。这个方法不但支持传入数组,将数组转成Stream,也支持传入多个参数,将参数最终转成Stream

Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};

long count = Stream.of(array).filter(i->i>20).count();

long sum = Stream.of(12,77,59,3,654).filter(i->i>20).mapToInt(Integer::intValue).sum();

System.out.println("count:"+count+",sum:"+sum);

3. Collection.stream()

这个就是最常见的Stream了。因为Collection是Java中集合接口的父接口,Java中的集合都继承或实现了此接口。所以Java中的集合都可以使用此方法来创建一个Stream

List numbers = new ArrayList<>();

numbers.add(3);

numbers.add(4);

numbers.add(8);

numbers.add(16);

numbers.stream().forEach(number->{

System.out.println(number);

});

4.filter

这是一个Stream的过滤转换,此方法会生成一个新的流,其中包含符合某个特定条件的所有元素,filter接受一个函数作为参数,该函数用Lambda表达式表示

List integerList = Lists.newArrayList();

integerList.add(15);

integerList.add(32);

integerList.add(5);

integerList.add(232);

integerList.add(56);

List after = integerList.stream()

.filter(i->i>50)

.collect(Collectors.toList());

System.out.println(after);//232,56

5.map

map方法指对一个流中的值进行某种形式的转换。需要传递给它一个转换的函数作为参数

List integerList = Lists.newArrayList();

integerList.add(15);

integerList.add(32);

integerList.add(5);

integerList.add(232);

integerList.add(56);

//将Integer类型转换成String类型

List afterString = integerList.stream()

.map(i->String.valueOf(i)).collect(Collectors.toList());

6.flatMap

将多个Stream连接成一个Stream,这时候不是用新值取代Stream的值,与map有所区别,这是重新生成一个Stream对象取而代之

List words = new ArrayList();

words.add("your");

words.add("name");

public static Stream characterStream(String s){

List result = new ArrayList<>();

for (char c : s.toCharArray())

result.add(c);

return result.stream();

}

Stream> result = words.map(w -> characterStream(w));

//[['y', 'o', 'u', 'r'], ['n', 'a', 'm', 'e']]

Stream letters = words.flatMap(w -> characterStream(w));

//['y', 'o', 'u', 'r', 'n', 'a', 'm', 'e']

7.limit方法和skip方法

limit(n)方法会返回一个包含n个元素的新的流(若总长小于n则返回原始流)

skip(n)方法正好相反,它会丢弃掉前面的n个元素

用limit和skip方法一起使用就可以实现日常的分页功能:

List pageList = myList.stream()

.skip(pageNumber*pageSize)

.limit(pageSize).collect(Collectors.toList());

8.distinct方法和sorted方法

distinct方法会根据原始流中的元素返回一个具有相同顺序、去除了重复元素的流,这个操作显然是需要记住之前读取的元素。

List myTestList = Lists.newArrayList();

myTestList.add(10);

myTestList.add(39);

myTestList.add(10);

myTestList.add(78);

myTestList.add(10);

List distinctList = myTestList.stream()

.distinct().collect(Collectors.toList());

System.out.println("distinctList:"+distinctList);

运行结果:

distinctList:[10, 39, 78]

sorted方法是需要遍历整个流的,并在产生任何元素之前对它进行排序。因为有可能排序后集合的第一个元素会在未排序集合的最后一位。

List myTestList = Lists.newArrayList();

myTestList.add(39);

myTestList.add(78);

myTestList.add(10);

myTestList.add(22);

myTestList.add(56);

List sortList = myTestList.stream()

.sorted(Integer::compareTo).collect(Collectors.toList());

System.out.println("sortList:"+sortList);

运行结果:

sortList:[10, 22, 39, 56, 78]

9.Collect

collect在流中生成列表,map,等常用的数据结构

将一个流收集到一个List中,只需要这样写就可以。

List thereList = hereList.stream().collect(Collectors.toList());

收集到Set中可以这样用

Set thereSet = hereList.stream().collect(Collectors.toSet());

收集到Set时,控制Set的类型,可以这样。

TreeSet treeSet = hereList.stream()

.collect(Collectors.toCollection(TreeSet::new));

10.聚合操作

聚合是指将流汇聚为一个值,以便在程序中使用。聚合方法都是终止操作,聚合方法包括sum,count,max,min

long sum = Stream.of(12,77,59,3,654).filter(i->i>20).mapToInt(Integer::intValue).sum();

findFirst方法返回非空集合中的第一个值,它通常与filter方法结合起来使用

Integer first = hearList.stream().filter(i->i>100).findFirst().get();

findAny方法可以在集合中只要找到任何一个所匹配的元素,就返回,此方法在对流并行执行时十分有效

Integer anyItem = hearList.parallelStream().filter(i->i>100).findAny().get();

11.分组

对具有相同特性的值进行分组是一个很常见的功能

将一个Room对象集合按照高度分组。

List roomList = Lists.newArrayList(

new Room(11,23,56),

new Room(11,84,48),

new Room(22,46,112),

new Room(22,75,62),

new Room(22,56,75),

new Room(33,92,224));

Map> groupMap = roomList.stream().collect(Collectors.groupingBy(Room::getHigh));

System.out.println("groupMap:"+groupMap);

2.3 Stream流的处理顺序

Stream流的中间操作具有延迟性,当且仅当存在终端操作时,中间操作才会被执行

Stream.of("d2", "a2", "b1", "b3", "c")

.filter(s -> {

System.out.println("filter: " + s);

return true;

});

执行此代码段时,不会打印任何内容,对上面的代码添加 forEach终端操作,就有打印内容了

Stream.of("d2", "a2", "b1", "b3", "c")

.filter(s -> {

System.out.println("filter: " + s);

return true;

})

.forEach(s -> System.out.println("forEach: " + s));

filter: d2

forEach: d2

filter: a2

forEach: a2

filter: b1

forEach: b1

filter: b3

forEach: b3

filter: c

forEach: c

但是可以看到输出结果并不是先将所有filter操作的打印语句打印出来;事实上,输出的结果却是随着链条垂直移动的,比如说,当 Stream 开始处理 d2 元素时,它实际上会在执行完 filter 操作后,再执行 forEach 操作,接着才会处理第二个元素

原因是出于性能的考虑。这样设计可以减少对每个元素的实际操作数,比如下面操作

Stream.of("d2", "a2", "b1", "b3", "c")

.map(s -> {

System.out.println("map: " + s);

return s.toUpperCase(); // 转大写

})

.anyMatch(s -> {

System.out.println("anyMatch: " + s);

return s.startsWith("A"); // 过滤出以 A 为前缀的元素

});

// map: d2

// anyMatch: D2

// map: a2

// anyMatch: A2

终端操作 anyMatch()表示任何一个元素以 A 为前缀,返回为 true,就停止循环。所以它会从 d2 开始匹配,接着循环到 a2 的时候,返回为 true ,于是停止循环。

由于数据流的链式调用是垂直执行的,map这里只需要执行两次。相对于水平执行来说,map会执行尽可能少的次数,而不是把所有元素都 map 转换一遍

stream --> filter --> map --> sorted --> collect

2.4 并行流

和迭代器不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item;

Stream具有平行处理能力,处理的过程会分而治之,也就是将一个大任务切分成多个小任务,这表示每个任务都是一个操作

//parallel方法可以将任意的串行流转换为一个并行流

Stream.of(roomList).parallel();

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

numbers.parallelStream()

.forEach(out::println);

//展示顺序不一定会是1、2、3、4、5、6、7、8、9,而可能是任意的顺序

最后

大家看完有什么不懂的欢迎在下方留言讨论

java lambda有必要_深度分析:java8的新特性lambda和stream流,看完你学会了吗?相关推荐

  1. springboot怎么返回404_深度分析:SpringBoot异常捕获与封装处理,看完你学会了吗?...

    简介 日常开发过程中,难免有的程序会因为某些原因抛出异常,而这些异常一般都是利用try ,catch的方式处理异常或者throw,throws的方式抛出异常不管.这种方法对于程序员来说处理也比较麻烦, ...

  2. java 8 stream_深度分析:java8的新特性lambda和stream流,看完你学会了吗?

    1. lambda表达式 1.1 什么是lambda 以java为例,可以对一个java变量赋一个值,比如int a = 1,而对于一个方法,一块代码也是赋予给一个变量的,对于这块代码,或者说被赋给变 ...

  3. 五十八、Java8的新特性Lambda表达式

    @Author:Runsen @Date:2020/6/24 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  4. Java8.0 新特性二之Stream

    Stream流 概述 说道Stream便容易想到I/O Stream, 而实际上,谁规定"流" 就一定是"IO流"呢?在Java8中,得益于Lambda所带来的 ...

  5. Java8新特性:使用Stream流递归实现遍历树形结构

    作者:Lcry blog.csdn.net/qq_19244927/article/details/106481777 可能平常会遇到一些需求,比如构建菜单,构建树形结构,数据库一般就使用父id来表示 ...

  6. python画米老鼠图片_简笔画:如何使用Flash绘制米老鼠,看完你学会了么

    米老鼠,是迪士尼的形象代表,它以随和乐观的性格受到了广大观众的喜爱.现在,我们以实际的例子出发,看看如何使用Flash绘制米老鼠卡通图案吧. 工具/材料 Flash 操作方法 01 新建文档 双击桌面 ...

  7. linux hashmap,Java中对HashMap的深度分析与比较

    Java中对HashMap的深度分析与比较 在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键.由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问 ...

  8. 深圳Java培训学习:Java8.0新特性之Lambda表达式--【千锋】

    深圳Java培训学习:Java8.0新特性之Lambda表达式–[千锋] 前言 Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.本篇文章,主要给大家介绍的是lambda表 ...

  9. java lambda表达式详解_Java8新特性Lambda表达式详解

    课程目标: 通过本课程的学习,详细掌握Java8新特性之Lambda表达式: 适用人群:有Java基础的开发人员: 课程概述:从Java 8出现以来lambda是最重要的特性之一,它可以让我们用简洁流 ...

  10. 学习笔记之-java8的新特性-函数式接口,lambda表达式,方法引用,Stream API,Optional类

    1.Lambda表达式 用匿名内部类的方法去创建多线程1.new Thread2.参数传递new Runnable3.重写run方法4.在run方法中去设置线程任务5.调用start问题:我们最终目标 ...

最新文章

  1. Hadoop对Spark:正面比拼报告(架构、性能、成本、安全性和机器学习)
  2. 看看那些令人惊艳的入库方案
  3. 自学python要看哪些书籍-Python入门自学到精通需要看哪些书籍?
  4. 链接服务器 '(null)' 的 OLE DB 访问接口'STREAM' 返回了对列 '[!BulkInsert].field' 无效的数据...
  5. 括号匹配问题(C++、堆栈)
  6. javascript window.close() 去掉那讨厌的确认对话框【转】
  7. 面试时遇到一致性哈希算法这样回答会让面试官眼前一亮
  8. centos ipv6 网卡_Linux_03-Centos的基本网络配置
  9. 苹果电脑屏幕刷新率如何调整
  10. 高亮插件Highlighting的使用
  11. 【论文速览】PV-RCNN: Point-Voxel Feature Set Abstraction for 3D Object Detection
  12. 实现button按钮的内容为图片
  13. Postman批量参数化测试
  14. 微信小程序开放平台代码部署特约商户
  15. 由滤波器系数绘制尺度函数和小波函数图像的Matlab程序
  16. SSL证书概述与配置
  17. 全球及中国电动车头盔行业销售前景态势及投资盈利分析报告2021-2027年
  18. 蓝奏批量自定义域名替换源码
  19. Python数据分析---回力评论关键字统计并制作词云图
  20. 怎么批量转换图片格式?这篇文章或许有用

热门文章

  1. 头条限流是什么原因_教训:千万不要用百家号去绑定头条号,后果你想象不到...
  2. 悟道web标准:前端性能优化
  3. HOWTO For iSCSI-SCST Gentoo HOWTO For iSCSI-SCST
  4. 烂泥:apache虚拟主机的学习与应用
  5. AWS表示:我们将用Lambda函数让移动应用程序再次变得伟大
  6. 使用Python解析JSON详解
  7. 嗯嗯------摘抄
  8. 在 Visual Studio 2010 中配置SharpPcap
  9. Vmware+Virtualbox+Ubuntu+debian+USB转串口+kermit
  10. 使用fastcgi_cache加速你的Nginx网站