java8实战 lambda表达式、函数式接口、方法引用双冒号(中)

前言

书接上文,上一篇博客讲到了lambda表达式的应用场景,本篇接着将java8实战第三章的总结。建议读者先看第一篇博客

其他函数式接口例子

上一篇有讲到Java API也有其他的函数式接口,书里也举了2个例子,一个是java.util.function.Consumer<T>, 定义了accpet抽象方法,接受泛型T对象,没有返回,一个是java.util.function.Function<T,R>,定义了apply方法,接受一个泛型T对象,返回泛型R对象

用consumer模拟forEach方法 

@FunctionalInterface
public interface Consumer<T>{void accept(T t);
}
public static <T> void forEach(List<T> list, Consumer<T> c){\for(T i: list) {c.accept(i);}
}
forEach(Arrays.asList(1,2,3,4,5),(Integer i)->System.out.println(i));

用Function来模拟map方法

@FunctionalInterface
public interface Function<T, R>{R apply(T t);
}
public static <T, R> List<R> map(List<T> list, Function<T, R> f){\List<R> result = new ArrayList<>();for(T s:list){result.add(f.apply(s));}return result;
}
List<Integer> l=map( Arrays.asList("lambdas","in","action"), (String s)->s.length());

常用的函数式接口

因为很多泛型函数式接口,如Predicate<T>,Consumer<T>, 其中T只能绑定要引用类型(如Byte,Integer,Object),不能绑定到原始类型(如int,double,byte,char),所以最后一栏有原始类型特化,对比一下例子:

也就是说IntPredicate是当T=int原始类型的特殊情况。

public interface IntPredicate{boolean test(int t);
}IntPredicate evenNumbers = (int i) -> i % 2 == 0;evenNumbers.test(1000);Predicate<Integer> oddNumbers = (Integer i) -> i % 2 == 1;oddNumbers.test(1000);

 lambda及函数式接口例子

 

 异常捕获的处理

由于任何函数式接口都不允许抛出受检异常,所以需要在lambda表达式抛出异常,如:

Function<BufferedReader, String> f = (BufferedReader b) -> {try{return b.readline();}catch(IOException e) {throw new RuntimeException(e);}}

使用局部变量

lambda可以没有限制地捕获实例变量和静态变量,但是局部变量必须显式声明为final或者事实上是final,如,下面代码无法编译,因为portNumber变量被赋值两次:

int portNumber = 1337;
Runnable r = () -> System.out.println(portnumber);
portNumber = 31337;

这一限制其实背后是因为实例变量是存储在堆上,而局部变量是保持在栈上,如果lambda可以直接访问局部变量,而且lambda是在一个线程中使用的,则使用lambda的线程,可能会在分配该变量的线程将这个变量收回以后,去访问该变量。

方法引用 

inventory.sort(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());//使用方法引用
inventory.sort(comparing(Apple::getWeight));

实际上方法引用是lambda的一种快捷写法,基本思想就是,如果一个lambda代表只是“直接调用这个方法”,那么最好还是用名称去调用它,而不是去描述如何调用它。

直观一点,可以认为:

Apple::getWeight 等于 (Apple a) -> a.getWeight()

书本也举了一些例子

总结:方法引用就是lambda只调用特定方法时候一种快捷写法,上述的例子中lambda主体只有调用一个函数。

如何构建方法引用

 方法引用有三类

1.指向静态方法的方法引用(如Integer的parseInt方法,写作Integer::parseInt)

2.指向任意类型实例方法的方法引用(如string的length方法,写作String::length)

3.指向现有对象的实例方法的方法引用(假设有一个局部变量expensiveTransaction用于存放Transanction类型的对象,它支持实例方法getValue, 那么你就可以写expensiveTransaction::getValue)

 书中还有图来表达这三类:

构造函数引用

 对于一个现有构造函数,可以利用它的名称和关键字new来创建它的一个应用:ClassName::new,它的功能与指向静态方法的引用类似。假设一个构造函数没有参数,适合Supplier的签名()->Apple

Supplier<Apple> c1 = Apple::new; //指向默认Apple()的构造函数
Apple a1 = c1.get(); //产生一个新的apple等价于Supplier<Apple> c1 = () -> new Apple();
Apple a1 = c1.get(); //产生一个新的apple

如果构造函数是Apple(Integer weight), 那么它就适合Function接口的签名

Function<Integer, Apple> c2 = Apple::new; //指向Apple(Integer weight)的构造函数
Apple a2 = c2.apply(110); //输入重量产生一个新的apple等价于Function<Integer Apple> c2 = (weight) -> new Apple(weight);
Apple a2 = c2.get(); //产生一个新的apple

以此类推,如果有两个参数,就可以用BiFunction接口,那么如果多个参数,那么就需要自己构造了,可以参考第一篇的构造一个接口。

最后有个有趣的应用,将上面知识点串在一起,比如说给定一个水果名称和重量,创建一个水果的实例,我个人想到最简单粗暴的方式,写if/else语句,判断水果名称,然后就是new不同的水果,当然也可以结合上面知识点,将new这个起始动作(还没new)放在map中,实际要用时候再apply.

static Map<String, Function<Integer, Fruit>> map = new HashMap<>();
static {map.put("apple", Apple::new);map.put("orange", Orange::new);
//etc...
}public static Fruit giveMeFruit(String fruit,  Integer weight) {return map.get(fruit.toLowerCase()).apply(weight);
}

第三章还有最后的实战部分,放到最后一篇讲。

参考文献:

《java8 实战》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/223717.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu系统如何安装和卸载CUDA和CUDNN

背景 最近在学习PaddlePaddle在各个显卡驱动版本的安装和使用&#xff0c;所以同时也学习如何在Ubuntu安装和卸载CUDA和CUDNN&#xff0c;在学习过程中&#xff0c;顺便记录学习过程。在供大家学习的同时&#xff0c;也在加强自己的记忆。本文章以卸载CUDA 8.0 和 CUDNN 7.05 …

Docker 编译OpenHarmony 4.0 release

一、背景介绍 1.1、环境配置 编译环境&#xff1a;Ubuntu 20.04OpenHarmony版本&#xff1a;4.0 release平台设备&#xff1a;RK3568 OpenHarmony 3.2更新至OpenHarmony 4.0后&#xff0c;公司服务器无法编译通过&#xff0c;总是在最后几十个文件时报错,错误码4000&#xf…

Linux一行命令配置jdk环境

使用方法&#xff1a; 压缩包上传 到/opt, 更换命令中对应的jdk包名即可。 注意点&#xff1a;jdk-8u151-linux-x64.tar.gz 解压后名字是jdk1.8.0_151 sudo tar -zxvf jdk-8u151-linux-x64.tar.gz -C /opt && echo export JAVA_HOME/opt/jdk1.8.0_151 | sudo tee -a …

Diffusion扩散模型学习:图片高斯加噪

高斯分布即正态分布&#xff1b;图片高斯加噪即把图片矩阵每个值和一个高斯分布的矩阵上的对应值相加 1、高斯分布 np.random.normal 一维&#xff1a; import numpy as np import matplotlib.pyplot as pltdef generate_gaussian_noise(mean, std_dev, size):noise np.ran…

【CentOS 7.9 分区】挂载硬盘为LVM操作实例

LVM与标准分区有何区别&#xff0c;如何选择 目录 1 小系统使用LVM的益处&#xff1a;2 大系统使用LVM的益处&#xff1a;3 优点&#xff1a;CentOS 7.9 挂载硬盘为LVM操作实例查看硬盘情况格式化硬盘创建PV创建VG创建LV创建文件系统并挂载自动挂载添加&#xff1a;注意用空格间…

VSCode SSH 连接提示: spawn UNKNOWN

随笔记录 目录 1. 背景介绍 2. 确认问题 : ssh -V 3. 解决问题 3.1 确认本地 ssh.exe 路径 3.2 修改vscode Remote.ssh:Path 3.2.1 设置 Reomte.ssh:Path - 方法一 3.2.2 设置 Reomte.ssh:Path - 方法二 1. 背景介绍 windows 系统vscode ssh remote CentOS7&#xff…

【零基础入门Docker】什么是Dockerfile Syntax

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门Docker专栏https://blog.csdn.net/arthas777/category_12455882.html 目录 编写Dockerfile和Format的语法 2. MAINTAINER 3. RUN 4. ADD 6. ENTRYPOINT 7. CMD 8. EXPOSE 9. VOLUME 11. USER 12. ARG …

.NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式

之前写过使用自定义返回类的方式来统一接口数据返回格式&#xff0c;.Net Core webapi RestFul 统一接口数据返回格式-CSDN博客 但是这存在一个问题&#xff0c;不是所有接口会按照定义的数据格式返回&#xff0c;除非每个接口都返回我们自定义的类&#xff0c;这种实现起来不…

Adobe InDesign各版本安装指南

下载链接 https://pan.baidu.com/s/1VWGKDUijTTETU9sVWFjCtg?pwd0531 #2024版本 1.鼠标右击【InCopy2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 InCopy2024(64bit)】。 2.打开解压后的文件夹&#xff0c;鼠标右击【Setup…

DevOps系列文章 : 使用dpkg命令打deb包

创建一个打包的目录&#xff0c;类似rpmbuild&#xff0c;这里创建了目录deb_build mkdir deb_build目标 我有一个hello的二进制文件hello和源码hello.c, 准备安装到/opt/helloworld目录中 步骤 在deb_build目录创建一个文件夹用于存放我的安装文件 mkdir helloworld在he…

深入探讨多模态模型和计算机视觉

近年来&#xff0c;机器学习领域在从图像识别到自然语言处理的不同问题类型上取得了显着进展。然而&#xff0c;这些模型中的大多数都对来自单一模态的数据进行操作&#xff0c;例如图像、文本或语音。相比之下&#xff0c;现实世界的数据通常来自多种模态&#xff0c;例如图像…

【Linux】Linux常见指令解析上

目录 1. 前言2. ls指令3. pwd指令4. cd指令3.1 cd常见快捷指令 4. touch指令5. mkdir指令6. rmdir指令 && rm指令 &#xff08;重要&#xff09;6.1 rmdir指令6.2 rm指令 7. man指令 1. 前言 这篇文章我们将详细介绍一下Linux下常见的基本指令。 2. ls指令 语法: ls [选…

系列一、GitHub搜索技巧

一、GitHub搜索技巧 1.1、概述 作为程序员&#xff0c;GitHub大家应该都再熟悉不过了&#xff0c;很多时候当我们需要使用某一项技能而又无从下手时&#xff0c;通常会在百度&#xff08;面向百度编程&#xff09;或者在GitHub上通过关键字寻找相关案例&#xff0c;比如我想学…

Go自定义PriorityQueue优先队列使用Heap堆

题目 分析 每次找最大的&#xff0c;pop出来 然后折半&#xff0c;再丢进去 go写法 go如果想用heap&#xff0c;要实现less\len\swap\push\pop 但可以偷懒&#xff0c;用sort.IntSlice,已经实现了less\len\swap 但由于目前是大根堆&#xff0c;要重写一下less 因此&#xff…

PWM/PFM 自动切换升压型转换器系统(一)

通过对芯片整体设计要求的考虑&#xff0c;搭建全负载高效率升压型 DC-DC 转换器的整体系 统框架&#xff0c;对系统的工作过程和模块电路的功能进行简要阐述&#xff0c;对外围电路的选取进行准确计 算&#xff0c;分析系统的损耗来源&#xff0c;实现高效率的设计目标。 芯片…

机场信息集成系统系列介绍(8):基于视频分析的航班保障核心数据自动采集系统

目录 一、背景 二、相关功能规划 1、功能设计 2、其他设计要求 三、具体保障数据采集的覆盖点 四、相关性能指标要求 1、性能指标要求 2、算法指标要求 一、背景 基于视频分析的航班保障核心数据自动化采集系统&#xff0c;是ACDM系统建设的延伸&#xff0c;此类系统并…

Uniapp + Vue3 + Pinia + Vant3 框架搭建

现在越来越多项目都偏向于Vue3开发&#xff0c;想着uniapp搭配Vue3试试效果怎么样&#xff0c;接下来就是详细操作步骤。 初始化Uniapp Vue3项目 App.vue setup语法 <script setup>import {onLaunch,onShow,onHide} from dcloudio/uni-apponLaunch(() > {console.l…

LeetCode 热题100——单调栈

​ 个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C语言小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 写在前面&#xff1a; 递增单调栈&#xff1a;栈中元素从栈底到栈顶依次增大 递减单调栈…

【新版】软考 - 系统架构设计师(总结笔记)

个人总结学习笔记&#xff0c;仅供参考&#xff01;&#xff01;&#xff01;! →点击 笔者主页&#xff0c;欢迎关注哦&#xff08;互相学习&#xff0c;共同成长&#xff09; 笔记目录 &#x1f4e2;【系统架构设计系列】系统架构设计专业技能 计算机组成与结构操作系统信…

【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. Java的注释方式二. 标识符三. 关键字四. 全篇总结 &#x1f4d1;前言 在Java编程…