【Java】Java 中的方法引用写法

概述

方法引用(MethodReference)是Lambda表达式的另一种格式,在某些场景下可以提高代码的可读性

使用条件

只可以替换单方法的Lambda表达式

什么意思呢 ?

例如下面这个Lambda表达式就不可以使用方法引用替换,因为其不是单方法的,有好几行呢。如果想要使用方法引用就需要将Lambda结构体重构为一个方法。

Predicate<Integer> p2 = integer -> {System.out.println("Hello World");return TestUtil.isBiggerThan3(integer);};

下面这个就可以使用方法引用替换了

Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);

使用场景

当使用方法引用替换Lambda表达式具有更好的可读性时,考虑使用。

方法引用的类型

方法引用可以分为分四类,只要掌握了类型区别一切就变得易如反掌了。为行文方便,这里先列出要使用的类:

TestUtil 里面有一个静态方法,一个实例方法。Student 是一个普通实体类,具体如下代码所示

public class MethodReference {...//示例类public static class TestUtil {public static boolean isBiggerThan3(int input) {return input > 3;}public void printDetail(Student student) {System.out.println(student.toString());}}public static class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getStatus(String thing) {return String.format("%d岁的%s正在%s", age, name, thing);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}}
}

调用类的静态方法

Lambda 表达式的那个单方法是某个类的静态方法

有如下格式,args 是参数,可以是多个,例如(a1,a2,a3)

Lambda:

(args) -> Class.staticMethod(args)

Method Reference:

Class::staticMethod

符合上面形式的调用,不管有多少参数,都省略掉,编译器自动会帮我们传入

看看下面的实例代码,其中 isBiggerThan3 是TestUtil 类的 static 方法。从上面的代码你可以清晰的看到,方法从匿名类到 Lambda 再到方法引用的演变。

public void testStaticMethodRef() {//匿名内部类形式Predicate<Integer> p1 = new Predicate<Integer>() {@Overridepublic boolean test(Integer integer) {return TestUtil.isBiggerThan3(integer);}};//lambda表达式形式Predicate<Integer> p2 = integer -> TestUtil.isBiggerThan3(integer);//MethodReference形式Predicate<Integer> p3 = TestUtil::isBiggerThan3;Stream.of(1, 2, 3, 4, 5).filter(p3).forEach(System.out::println);
}

调用传入的实例参数的方法

Lambda:

(obj, args) -> obj.instanceMethod(args)

Method Reference:

ObjectType::instanceMethod

看到我们 Lambda 的入参 obj 了吗?它是一个类型,假设为 ObjectType,的实例对象。然后再看 Lambda 表达式,是在调用此实例 obj 的方法。这种类型的 Lambda 就可以写成上面的形式了,看起来和静态方法那个一样。

来看看下面的实例代码

public void testInstanceMethodRef1() {//匿名类BiFunction<Student, String, String> f1 = new BiFunction<Student, String, String>() {@Overridepublic String apply(Student student, String s) {return student.getStatus(s);}};//lambdaBiFunction<Student, String, String> f2 = (student, s) -> student.getStatus(s);//method referenceBiFunction<Student, String, String> f3 = Student::getStatus;System.out.println(getStudentStatus(new Student("erGouWang", 18), "study", f3));
}
private String getStudentStatus(Student student, String action, BiFunction<Student, String, String> biFunction) {return biFunction.apply(student, action);
}

调用已经存在的实例的方法

Lambda:

(args) -> obj.instanceMethod(args)

Method Reference:

obj::instanceMethod

我们观察一下我们 Lambda 表达式,发现obj对象不是当做参数传入的,而是已经存在的,所以写成方法引用时就是实例::方法

来看看下面的实例代码,可见 utilObj 对象是我们提前 new 出来的,是已经存在了的对象,不是 Lambda 的入参。

public void testInstanceMethodRef2() {TestUtil utilObj = new TestUtil();//匿名类Consumer<Student> c1 = new Consumer<Student>() {@Overridepublic void accept(Student student) {utilObj.printDetail(student);}};//Lambda表达式Consumer<Student> c2 = student -> utilObj.printDetail(student);//方法引用Consumer<Student> c3 = utilObj::printDetail;//使用consumeStudent(new Student("erGouWang", 18), c3);
}private void consumeStudent(Student student, Consumer<Student> consumer) {consumer.accept(student);
}

调用类的构造函数

Lambda:

(args) -> new ClassName(args)

Method Reference:

ClassName::new

当 Lambda 中的单方法是调用某个类的构造函数,我们就可以将其写成如上形式的方法引用。

public void testConstructorMethodRef() {BiFunction<String, Integer, Student> s1 = new BiFunction<String, Integer, Student>() {@Overridepublic Student apply(String name, Integer age) {return new Student(name, age);}};//lambda表达式BiFunction<String, Integer, Student> s2 = (name, age) -> new Student(name, age);//对应的方法引用BiFunction<String, Integer, Student> s3 = Student::new;//使用System.out.println(getStudent("cuiHuaNiu", 20, s3).toString());
}private Student getStudent(String name, int age, BiFunction<String, Integer, Student> biFunction) {return biFunction.apply(name, age);
}

来看看下面的实例代码,上面代码值得注意的就是,Student 类必须有一个与 Lambda 入参相匹配的构造函数。例如此例中,(name, age) -> new Student(name, age); 需要两个入参的构造函数,为什么呢?

因为我们的 Lambda 表达式的类型是 BiFunction,而其正是通过两个入参来构建一个返回的。其签名如下:

@FunctionalInterface
public interface BiFunction<T, U, R> {R apply(T t, U u);...
}

通过入参 (t,u) 来生成 R 类型的一个值。

我们可以写一个如下的方法引用:

Function<String, Student> s4 = Student::new;

但是IDE就会报错,提示我们的 Student 类没有对应的构造函数,我们必须添加一个如下签名的构造函数才可以

public Student(String name) {this.name = name;
}

补充

下面这段代码是一个Spring Security的配置类,可以看到在这段代码中用到了this::onAuthenticationSuccess,this::onAuthenticationFailure,this::onLogoutSuccess这样的方法引用写法。

具体来说,this::onAuthenticationSuccess 表示引用当前类中的 onAuthenticationSuccess 方法。

这里使用 this 表示当前对象(通常是一个类的实例),:: 是方法引用操作符,onAuthenticationSuccess 则是方法的名称。

在 Spring Security 配置中,使用方法引用可以简洁地传递方法作为参数,而不必显式地编写 lambda 表达式。在这种情况下,this::onAuthenticationSuccess 会将当前类的 onAuthenticationSuccess 方法作为参数传递给 successHandler 方法。

/*** @ClassName : SecurityConfiguration* @Description : Security配置* @Author : LYQ* @Date: 2024-02-17 19:24*/
@Configuration
public class SecurityConfiguration {@Autowiredprivate JwtUtils jwtUtils;@Autowiredprivate JwtAuthorizeFilter jwtAuthorizeFilter;@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {return http.authorizeHttpRequests(conf -> conf.requestMatchers("/api/auth/**").permitAll().anyRequest().authenticated()).formLogin(conf -> conf.loginProcessingUrl("/api/auth/login").successHandler(this::onAuthenticationSuccess).failureHandler(this::onAuthenticationFailure)).logout(conf -> conf.logoutUrl("/api/auth/logout").logoutSuccessHandler(this::onLogoutSuccess)).exceptionHandling(conf -> conf.accessDeniedHandler(this::onAccessDeny).authenticationEntryPoint(this::onUnauthorized)).csrf(AbstractHttpConfigurer::disable).sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).addFilterBefore(jwtAuthorizeFilter, UsernamePasswordAuthenticationFilter.class).build();}public void onAccessDeny(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.setContentType("application/json;charset=UTF-8");response.getWriter().write(RestBean.forbidden(accessDeniedException.getMessage()).asJsonString());}public void onUnauthorized(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {response.setContentType("application/json;charset=UTF-8");response.getWriter().write(RestBean.unauthorized(exception.getMessage()).asJsonString());}public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json");response.setCharacterEncoding("utf-8");User user = (User) authentication.getPrincipal();String token = jwtUtils.createJwt(user, 1, "MrVK");AuthorizeVO vo = new AuthorizeVO();vo.setExpire(jwtUtils.expireTime());vo.setRole("");vo.setToken(token);vo.setUsername("MrVK");response.getWriter().write(RestBean.success(vo).asJsonString());}public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().write(RestBean.unauthorized(exception.getMessage()).asJsonString());}public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();String authorization = request.getHeader("Authorization");if(jwtUtils.invalidateJwt(authorization)) {writer.write(RestBean.success("退出登录成功").asJsonString());return;}writer.write(RestBean.failure(400, "退出登录失败").asJsonString());}
}

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

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

相关文章

100243. 将元素分配到两个数组中 I

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 题目描述 给你一个下标从 1 开始、包含 不同 整数的数组 nums &#xff0c;数组长度为 n 。 你需要通…

C语言 快速排序——qsort函数的介绍

qsort函数 1. 函数介绍2. 函数使用2.1 整型排序2.2 字符排序2.3 字符串排序2.4 结构体排序 3. 用冒泡思想模拟qsort函数 我们以往使用冒泡排序和选择排序等对数据进行排序时&#xff0c;有可能会遇到搞不清排序次数&#xff0c;运行时间过长等一些问题&#xff0c;并且这些排序…

aop监控spring cloud接口超时,并记录到数据库

引入pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0…

宝塔面板安装各种组件以及部署应用服务

在linux服务器安装宝塔面板 一、从宝塔官网下载exe安装包&#xff0c;安装命令从宝塔官网&#xff08;https://www.bt.cn/&#xff09;获取 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh二、安…

自动驾驶加速落地,激光雷达放量可期(上)

1 激光雷达应用广泛&#xff0c;汽车有望成最大催化 激光雷达&#xff08;LiDAR&#xff09;是一种主动遥感技术&#xff0c;通过测定传感器发出的激光在传感器与目标物体之间的传播距离&#xff0c;来分析目标地物表面的反射能量大小、反射波谱的幅度、频率和相位等信息&#…

Vue项目如何进行优化?

Vue项目优化 1.移除控制台打印2.压缩图片3.CDN加速 1.移除控制台打印 可以使用插件自动去除&#xff0c;插件包括babel-plugin-transform-remove-console、uglifyjs-webpack-plugin、terser-webpack-plugin。最后选择了terser-webpack-plugin&#xff0c;脚手架vue-cli用这个插…

一文扫盲:订单管理系统,订单是公司生命线。

hello&#xff0c;我是贝格前端工场&#xff0c;本期给大家分享订单管理系统的知识点&#xff0c;欢迎老铁们点赞、关注&#xff0c;如有需求可以私信我们。 一、什么是订单管理系统 单管理系统是一种用于管理和处理订单的软件系统。它通常用于企业、电子商务平台、零售店等需…

高并发高可用--反向代理与负载均衡

高并发高可用架构是指能够应对大量并发请求并保持高度可用的系统架构。为了实现这一目标&#xff0c;通常会采用一系列技术和策略&#xff0c;包括负载均衡、缓存、分布式系统、冗余部署、容错处理等。 以下是一些构建高并发高可用架构的关键要点&#xff1a; 负载均衡&#…

GEE高阶应用python wxee 和eemont——MODIS 中生成NDVI 数据的月度时序影像

结合 wxee 和 eemont eemont概述 谷歌地球引擎是一种基于云的服务,用于矢量和栅格数据的地理空间处理。地球引擎平台拥有 JavaScript 和 Python API,可使用不同方法处理地理空间对象。谷歌地球引擎还提供了一个巨大的 PETABYTE 级栅格和矢量数据目录,用户可以在线处理这些…

技术小知识:面向对象和过程的区别 ⑤

一、思想区别 面相对象&#xff1a;始终把所有事情思考归类、抽离封装成对象来调用完成。 面向过程&#xff1a;直接平铺展开按顺序执行完成任务。 面向对象多了很多对象的创建、使用&#xff0c;销毁的过程资源消耗。是一种模块化编程思想。 https://www.cnblogs.com/kuangmen…

网络爬虫弹幕

1.分析网页&#xff0c;获取代码&#xff0c;提取时间 想要提取出弹幕所在的节点&#xff0c;我们要使用 Beautiful Soup 解析模块&#xff0c;需要从 bs4 中导入 BeautifulSoup 模块 创建一个 BeautifulSoup 对象&#xff0c;传入变量 xml 和解析器 lxml&#xff0c;将该对象赋…

Java自学day5

流程控制语句 流程控制语句:通过一些语句,控制程序的执行流程 顺序结构 顺序结构语句是Java程序默认的执行流程,按照代码的先后顺序,从上到下依次执行! package orderdemo;public class OrderDemo {public static void main(String[] args) {System.out.println("…

2.2 mul、div、and、or乘除指令及所有寄存器英文名

汇编语言 1. mul乘指令 两个相乘的数&#xff0c;要么都是8位&#xff0c;要么都是16位 两个8位数相乘 一个默认放在al中&#xff0c;另一个放在8位reg或内存字节单元中8位乘法&#xff0c;结果默认放在ax中例如&#xff1a;计算100*10 100和10小于255&#xff0c;可以做8位…

一(四)班课表

第二学期 课节时间星期一星期二星期三星期四星期五上午18:20-9:00数学数学数学京剧语文29:10-9:50劳动音乐语文语文音乐310:30-11:10语文语文美术道德与法治数学思维411:20-12:00科学轮滑美术体育英语下午513:20-14:00数学实践活动音乐欣赏语文英语语文拓展614:10-14:50体育英语…

信息系统安全与对抗-作业2

目录 1、使用自己姓名拼音创建一个账户&#xff0c; 并使用命令和图形化查看 2、使用自己拼音打头字母创建一个隐藏账户 &#xff0c;并使用命令和图形化查看 3、使用命令启动 telnet 服务 4、使用命令打开防火墙 23 端口 5、熟悉LINUX系统&#xff0c;使用命令行创建用户…

Spring Cloud Nacos集成Seata2.0 AT模式

Spring Cloud Nacos集成Seata2.0 AT模式 以CentOS 7为例&#xff0c;介绍Spring Cloud Nacos集成Seata2.0 AT模式的流程。分成两个步骤&#xff1a;1.安装配置seata-server、2.项目集成seata-client 一、下载seata-server安装包 根据自己的操作系统选择要下载的安装包格式&a…

2023年第十四届蓝桥杯大赛软件类省赛C/C++大学A组真题

2023年第十四届蓝桥杯大赛软件类省赛C/C大学A组部分真题和题解分享 文章目录 蓝桥杯2023年第十四届省赛真题-平方差思路题解 蓝桥杯2023年第十四届省赛真题-更小的数思路题解 蓝桥杯2023年第十四届省赛真题-颜色平衡树思路题解 蓝桥杯2023年第十四届省赛真题-买瓜思路题解 蓝桥…

05-Linux部署MySQL

Linux部署MySQL 在今后的使用过程中&#xff0c;需要频繁使用Linux系统&#xff0c;所以在Linux上安装软是必不可少的操作 。 前置要求 需要学习前四章知识&#xff0c;初识Linux、Linux基础命令、Linux权限管理、Linux高阶技巧这4个章节。需要开启多态虚拟机&#xff0c;电…

KubeSphere简介,功能介绍,优势,架构说明及应用场景

KubeSphere 是在目前主流容器调度平台 Kubernetes 之上构建的企业级分布式多租户容器平台&#xff0c;提供简单易用的操作界面以及向导式操作方式&#xff0c;在降低用户使用容器调度平台学习成本的同时&#xff0c;极大减轻开发、测试、运维的日常工作的复杂度&#xff0c;旨…

每日一题 — 快乐数

202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 可以借用判断链表是否有环的思想&#xff1a; 定义快慢指针&#xff08;两个变量赋值就行&#xff09;快指针走两次&#xff0c;慢指针走一次快慢指针相遇&#xff0c;看是不是等于一 public int bitSum(…