lambda表达式和stream流

lambda表达式

基本格式

(Object o1, Object o2) -> {方法体}

o1、o2:方法参数

->:特定的箭头符号

{…}:方法体内容,实际的代码

注:当方法体只有一行时,花括号可省略。

函数式接口

函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

@FunctionalInterface

java提供上述注解标记一个接口为函数式接口,该注解为非强制添加注解,仅仅作为一个定义的条件约束,也就是说如果一个接口加上了该注解,那么该接口必须满足函数式接口的定义。

注:重写/定义父类的方法,不影响上述的判断规则,接口只要符合上述规则即可。

核心函数式接口

消费接口

Consumer

lambda表达式和stream流

顾名思义,该接口的accept方法实现要求传入一个泛型参数,在方法体中做出某些操作,无返回值(void),就像现实生活中的某些消费操作一样,把钱交给对方后,对方提供某些服务。该接口大多数用于集合遍历操作中(可以通过项目代码看出),对元素进行消费操作。

常见变种接口:

lambda表达式和stream流

生产接口

Supplier

lambda表达式和stream流

该接口get方法实现无入参,返回值为指定泛型类型,该接口可以用来生产元素。

常见变种接口:

lambda表达式和stream流

谓词接口

Predicate

lambda表达式和stream流

该接口test方法实现要求传入一个泛型参数t,返回值为boolean,因此该接口常常用来做元素的过滤和筛选。

常见变种接口:

lambda表达式和stream流

函数接口

Function

lambda表达式和stream流

该接口apply方法实现要求传入一个泛型参数t,返回值为另一个泛型类型R,该接口主要用来进行元素的映射和转换。

常见变种接口:

lambda表达式和stream流

类型检查

Lambda的类型是从使用Lambda的上下文推断出来的。上下文(比如,接受它传递的方法的参数,或接受它的值的局部变量)中Lambda表达式需要的类型称为目标类型。类型检查描述示例如下图所示(部分图例摘自《Java8实战》)。

lambda表达式和stream流

类型推断

Java编译器会从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式,这意味着它也可以推断出适合Lambda的签名(方法名+参数类型),因为函数描述符可以通过目标类型来得到。这样做的好处在于,编译器可以了解Lambda表达式的参数类型,这样就可以在Lambda语法中省去标注参数类型。类型推断示例如下图所示。

lambda表达式和stream流

方法引用

方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。它的基本思想是,如果一个Lambda代表的只是”直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。方法引用的一些例子如下图所示。

lambda表达式和stream流

方法引用构建方法主要有以下三类。

静态方法的调用

当调用类的静态方法时,可以简写为类名::方法名(不带括号)的格式。

额外补充说明如下:

无参静态方法调用

可以直接使用方法引用。

具体示例代码如下:

Test类静态方法:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流
带参的静态方法引用

调用的静态方法中的参数个数,必须要和lambda参数个数保持一致,且不能包含其他外部参数,否则无法使用方法引用。

具体示例代码如下:

Test类中带参的静态方法如下:

lambda表达式和stream流

Test2类中带参的静态方法如下:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

Test类静态方法,3个参数:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

lambda表达式中参数对象的实例方法调用

当调用lambda表达式中参数对象的实例方法时,可以简写为类名::调用方法名(不带括号)的格式。

额外补充说明如下:

无参实例方法调用

lambda参数仅有一个时,可以将其转换为方法引用;

若lambda参数多个,则无法转换为方法引用。

具体示例代码如下:

Test类,无参实例方法如下:

lambda表达式和stream流

TestInterface接口如下,test方法仅有一个参数:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

TestInterface1接口如下,test方法包含多个参数:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流
带参实例方法调用

lambda参数仅有一个时,无论实例方法参数类型和个数,均不能使用方法引用;

lambda参数为多个时,必须满足方法体中调用方法的对象为lambda参数的第一个参数,并且剩余的参数,类型和个数要和调用的方法的类型和个数匹配,且剩余参数均要在调用方法的其他参数列表里,个数只能出现一次,不允许出现其他外部参数。

具体示例代码如下:

Test类中,带参实例方法如下:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

lambda表达式和stream流

Test类中,带参实例方法如下:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

lambda表达式和stream流

将TestInterface接口的test方法修改为如下格式,包含3个参数:

lambda表达式和stream流

Test类main方法代码:

lambda表达式和stream流

外部实例对象的实例方法调用

当调用其他实例对象的实例方法时,可以简写为实例对象名::调用方法名(不带括号)的格式。

额外补充说明如下:

无参实例方法调用

不存在lambda参数时,可以使用方法引用;

存在lambda参数时,不可以使用方法引用。

具体示例代码如下:

TestInterface3接口如下:

lambda表达式和stream流

TestInterface4接口如下:

lambda表达式和stream流

Test类,main方法代码:

lambda表达式和stream流

lambda表达式和stream流
带参实例方法调用

不存在lambda参数时,无法使用方法引用;

存在lambda参数,且lambda参数和调用的实例方法参数类型、个数、顺序保持一致,则可以使用方法引用。

具体示例代码如下:

TestInterface接口代码如下:

lambda表达式和stream流

TestInterface3接口代码如下:

lambda表达式和stream流

Test类,实例方法如下:

lambda表达式和stream流

lambda表达式和stream流

Test类,main方法代码:

lambda表达式和stream流

lambda表达式和stream流

Stream流

基本概念

流是Java8新增的特性,简单来说,流能让你更加简单地对数据的集合进行排序、过滤、映射等处理。使用流有以下几点好处:声明性(代码更简洁、易读)、可复合(更灵活)、可并行(充分发挥性能)。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等;元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

可以将stream流操作想象成工厂里的流水线操作,原料经过一系列的流水线加工,最终包装成产品。

lambda表达式和stream流

中间/终端操作

java.util.stream.Stream中的Stream接口定义了许多操作,它们可以分为两大类,以下列代码举例说明:

List

.filter(d -> d.getCalories() > 300)(过滤)

.map(Dish::getName)(映射)

.limit(3)(取前3条数据)

.collect(toList());(聚合)

其中,filter、map和limit可以连成一条流水线;collect触发流水线执行并关闭它。

可以连接起来的流操作称为中间操作。诸如 filter 或 sorted 等中间操作会返回另一个流。这让多个操作可以连接起来形成一个查询。重要的是,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理(延迟操作)。这是因为中间操作一般都可以合并起来,在终端操作时一次性全部处理。

关闭流的操作称为终端操作。终端操作会从流的流水线生成结果,该结果是任何不是流的值,比如List、Integer甚至是void(如进行遍历操作)。

使用流的步骤

第一步:从一个数据源(如集合)调用指定方法,获取流对象;

第二步:对于流对象,可以有一个或多个中间操作链,形成一条流的流水线操作;

第三步:执行某个终端操作,流水线此时才开始执行,并生成结果。

流的创建

由值创建流:Stream.of()静态方法,传入对象/对象数组;

由数组创建流:Arrays.stream()静态方法,传入数组;

由文件创建流:Files.lines()静态方法,传入文件路径(Path);

由函数创建流:Stream. iterate()静态方法(迭代),Stream.generate()静态方法(生成)。

注:使用函数创建流时,一定要调用limit方法限制流元素的个数,否则流会无限生成元素,导致程序运行异常。

示例代码:

lambda表达式和stream流

收集器

Collector

接口部分源码如下

lambda表达式和stream流

泛型说明:

T:进行归约操作的元素类型;

A:归约操作的中间类型;

R:归约操作最终返回的类型。

方法说明:

supplier():流元素容器提供;

accumulator():流元素归约操作;

combiner():将两个部分结果合并到一个结果中。该方法适用于parallelStream()并行流;

finisher():将中间类型结果转换为最终类型;

characteristics():收集器的特性。

Original: https://www.cnblogs.com/yjry-th/p/13753225.html
Author: yjry-th
Title: lambda表达式和stream流

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/574599/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Redis学习笔记

    Redis学习 记录 1、NoSQL 数据库 NoSQL,泛指非关系型的数据库。 分类 键值(Key-Value)存储数据库 列存储数据库 文档型数据库 分类 Examples举例…

    Java 2023年6月7日
    081
  • [学习笔记] Java字符和字符串

    在Java中,字符和字符串是两种不同的数据类型; 字符 (char) 是一种基本数据类型,用单引号’ 括起来; 一个char类型可以保存一个标准的ASCII字符或一个U…

    Java 2023年6月5日
    075
  • 使用 Java Swing 编写 IpChat, 基于 IP Messenger 协议,支持 IPv4/IPv6

    最近一段时间居家办公,使用 Java Swing 编写 IpChat, 基于 IP Messenger 协议,支持 IPv4/IPv6。可实现简单的文本信息传输,点对点直接通讯,无…

    Java 2023年6月9日
    056
  • Spring Boot 整合 Redis

    创建redis缓存配置类,配置插件(较为固定) package com.xsha.servicebase; import com.fasterxml.jackson.annotat…

    Java 2023年6月7日
    049
  • iOS的Runtime知识点繁杂难啃,真的理解它的思想,你就豁然开朗了

    一、Runtime 1、概念: 概念:Runtime是Objective-c语言动态的核心,即运行时。在面向对象的基础上增加了动态运行,达到很多在编译时确定方法推迟到了运行时,从而…

    Java 2023年6月16日
    069
  • Spring Boot:整合Swagger文档

    综合概述 spring-boot作为当前最为流行的Java web开发脚手架,越来越多的开发者选择用其来构建企业级的RESTFul API接口。这些接口不但会服务于传统的web端(…

    Java 2023年5月30日
    088
  • java 递归转非递归(树形转非树形)

    接着上一篇讲,在上一篇我们已经将数据通过递归转成了树形结构。 如何将树形结构转非树形结构?(仍然按照树形层级关系进行平铺显示) 如何将递归函数转成迭代函数? 查看代码 [{ nam…

    Java 2023年5月29日
    0120
  • Java9的模块化是什么

    Java9中的一个重大特性是增加了一种新型的程序设计组件 – 模块。 官方对模块的定义为:一个被命名的,代码和数据的自描述集合。( the module, which …

    Java 2023年6月7日
    077
  • Springboot循环依赖实践纪实

    测试的Springboot版本: 2.6.4,禁止了循环依赖,但是可以通过 application.yml开启(哈哈) @Lazy注解解决循环依赖 情况一:只有简单属性关系的循环依…

    Java 2023年6月7日
    086
  • SpringCloud-Ribbon

    1. Ribbon简介 Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当使用Ribbon对服务进行访问的时候,他会扩展Eureka客户端的服务发现功能,实现从Eurek…

    Java 2023年6月7日
    073
  • Spring Boot【快速入门】

    转自: https://www.cnblogs.com/wmyskxz/p/9010832.html Spring Boot 概述 Build Anything with Spri…

    Java 2023年5月30日
    056
  • WCF 返回json的时间格式的转换

    有朋友用这个办法不错 1、把”\/Date(976723200000+0800)\/”中的976723200000提取出来,这一步无论是正则还是substr…

    Java 2023年6月14日
    077
  • BAT经典面试题之redis的热KEY问题怎么解决

    讲了几天的数据库系列的文章,大家一定看烦了,其实还没讲完。。。(以下省略一万字)。今天我们换换口味,来写redis方面的内容,谈谈热key问题如何解决。其实热key问题说来也很简单…

    Java 2023年6月15日
    074
  • java基础4.19

    1.JAVA 的反射机制的原理。JAVA反射机制是在运行状态中,对于 任意一个类,都能够 知道这个类的 所有属性和方法;对于任意一个对象,都能够调 用它的任意一个方法;这种 动态获…

    Java 2023年6月5日
    063
  • JDK成长记3:ArrayList常用方法源码探索(中)

    无论是程序员的工作、学习,还是生活中的事情。都可以遵循这样一条原则:”,简单的事情重复做,正确的事情重复做。” 这样的努力会让你走到正道上,少走很多弯路。从…

    Java 2023年6月5日
    084
  • Java GC 日志详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt105 java GC日志可以通过 +PrintGCDet…

    Java 2023年5月29日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球