JAVA方法引用:

  • 方法引用的出现原因在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作那么考虑一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑呢?答案肯定是没有必要那我们又是如何使用已经存在的方案的呢?这就是我们要讲解的方法引用,我们是通过方法引用来使用已经存在的方案

概述:

方法引用就是把已经有的方法拿过来用,当做函数式接口中的抽象方法的方法体
以后会在MybatisPlus这个框架中大量使用方法引用


如下过程就是方法引用:
要求:对Integer数组arr进行降序排序:
image.png
这时可以用方法引用 ,当做函数式接口中的抽象方法的方法体
image.png

public class Test01 {public static void main(String[] args) {Integer []arr={4,2,5,7,8};
//1.普通表达式
/*  Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}
});*///2.lambda表达式
/*Arrays.sort(arr, ((o1, o2) -> o2-o1));*///3.方法引用:
//表示引用Test01类里面的subtraction
//把这个方法当做抽象方法的方法体
Arrays.sort(arr,Test01::subtraction);
//打印
System.out.println(Arrays.toString(arr));//[8, 7, 5, 4, 2]}//可以是Java己经写好的,也可以是一些第三方的工具类public static int subtraction(Integer num1,Integer num2){return num2-num1;}
}

::是方法引用符


## 使用方法引用必须满足下面四点:
  1. 引用处必须是函数式接口
    1. 如上:Compartor是函数式接口
  2. 被引用的方法必须已经存在
    1. 如上:subtraction已手动创建
  3. 被引用的方法的形参和返回值要和抽象方法保持一致
  4. 被引用方法的功能必须满足需求

方法引用的分类:

引用静态方法:

格式:类名::静态方法名
如:Integer::parseInt

我们上面那个的例子其实也是引用静态方法

练习:
image.png

public class Test02 {public static void main(String[] args) {
//引用静态方法
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"1","2","3","4","5");
//类型转换可以用刚学的stream流中的中间方法map//1.普通表达式
/*List<Integer> newList = list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}
}).collect(Collectors.toList());*///2.方法引用
List<Integer> newList = list.stream().map(Integer::parseInt).collect(Collectors.toList());
//获取0索引看看可以运算吗
int num = newList.get(0) + 1;
System.out.println(num);//2,可以运算说明成功转为Integer类型了}
}

可以看看上面的方法引用是否满足四个要求:

  1. Function是函数式接口
    1. image.png
  2. 被引用的方法是java已存在的
  3. 被引用的parseInt方法的形参和返回值和抽象方法一致
    1. Snipaste_2024-02-03_10-50-16.png
  4. 被引用的方法的功能必须满足需求

引用成员方法

引用其他类的成员方法:

格式: 对象::成员方法

练习:
image.png

public class Test03 {public static void main(String[] args) {ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"张三","钱七","王五","张无忌","李四");//要求:过滤数据(只要以张开头,而且名字是3个字的)/*//普通写法
list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张")&&s.length()==3;}});*///方法引用
//创建对象:
StringOperation so=new StringOperation();
list.stream().filter(so::method).forEach(s -> System.out.println(s));//张无忌}
}
//其他类:
class StringOperation{//成员方法public boolean method(String s) {return s.startsWith("张")&&s.length()==3;}
}

引用本类的成员方法(引用处不能是静态)

格式:this::方法名

还是用上面这个例子:
此时将其他类的成员方法放到本类中,

public class Test03 {public static void main(String[] args) {ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"张三","钱七","王五","张无忌","李四");
//过滤数据(只要以张开头,而且名字是3个字的)/*//普通写法
list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张")&&s.length()==3;}});*///方法引用
//创建对象:
Test03 t=new Test03();
list.stream().filter(t::method).forEach(s -> System.out.println(s));//张无忌}//已放入本类public boolean method(String s) {return s.startsWith("张")&&s.length()==3;}}

这里同样满足四个要求:

  1. 引用处必须是函数时接口
  2. 被引用的方法已存在
  3. 被引用的方法的形参和返回值和抽象方法一样
  4. 功能满足需求

疑问:
不是说引用本类成员方法的格式是 this::方法名 吗
是的,但是本例子中的引用处是main方法,是静态的,而以前说过静态内没有this关键字,所以还是要创建本类对象再去用 对象名::方法名


引用父类的成员方法(引用处不能是静态)

格式:super::方法名

举例:
定义一个接口:Greetable


public interface Greetable {void greet();//问候的抽象方法
}

Person类


public class Person {//问候方法public void sayHello(){System.out.println("Hello! 我是人。");}
}

子类Teacher

public class Teacher extends Person {//重写父类方法@Overridepublic void sayHello() {System.out.println("Hello!,我是老师");}//定义一个方法,参数传递Gerrtable接口public void method(Greetable g) {g.greet();}public void show() {//调用method,//以前:使用匿名内部类的写法,调用父类的打招呼方法method(new Greetable() {@Overridepublic void greet() {Teacher.super.sayHello();}});//现在:方法引用method(super::sayHello);}
}

测试类:

class Test {public static void main(String[] args) {Teacher t = new Teacher();t.show();}
}

Hello! 我是人。
Hello! 我是人。


引用构造方法

格式:** 类名**::new
如:Student::new

练习:
image.png
Student类:

public class Student {//属性private String name;private int age;//构造public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}// ...set、get、toString
}

测试类:

public class Test04 {public static void main(String[] args) {//创建集合
ArrayList<String> list = new ArrayList<>();
//添加元素
Collections.addAll(list, "张三,23", "李四,24", "王五,25");
//普通写法
/*  List<Student> newList = list.stream().map(new Function<String, Student>() {@Overridepublic Student apply(String s) {return new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1]));}
}).collect(Collectors.toList());*///方法引用list.stream().map(Student::new);}
}

当我们在测试类中写到上面这一步时,new会报错,也就是说肯定是违背了方法引用的规则
image.png
可以发现抽象方法中只有一个形参,
而Student的构造方法只有无参或两个参,
这时我们就可以手动在Student中写一个只有一个形参的构造方法
如:
Student

public class Student {//属性private String name;private int age;//构造public Student() {}//其中str就表示流中的每个数据//调用构造方法时不用考虑返回值,因为该引用构造后一定会返回是否和抽象方法一致即可public Student(String str){this.name=str.split(",")[0];this.age=Integer.parseInt(str.split(",")[1]);}public Student(String name, int age) {this.name = name;this.age = age;}// ...set、get、toString
}
public class Test04 {public static void main(String[] args) {//创建集合
ArrayList<String> list = new ArrayList<>();
//添加元素
Collections.addAll(list, "张三,23", "李四,24", "王五,25");//普通写法
/*  List<Student> newList = list.stream().map(new Function<String, Student>() {@Overridepublic Student apply(String s) {return new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1]));}
}).collect(Collectors.toList());*///方法引用
List<Student> newList = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(newList);
//[Student{name = 张三, age = 23}, Student{name = 李四, age = 24}, Student{name = 王五, age = 25}]}
}

最后来看看Collectors的toList方法底层逻辑:
image.png
原来toList方法底层也是使用方法引用创建的ArrayList的对象
image.png

**其他方法引用的使用:

*使用类名引用成员方法(特殊):

格式:类名::成员方法
如:String::substring

练习:
image.png

//创建集合
ArrayList<String>list=new ArrayList<>();
Collections.addAll(list,"a","b");
//普通写法
//String->String,可以使用map方法
/*list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).forEach(s -> System.out.println(s));*///方法引用:
list.stream()
.map(String::toUpperCase)
.forEach(s -> System.out.println(s));

使用类名引用成员方法的特殊规则:

  1. 函数式接口
  2. 被引用方法已存在
  3. *被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参一致,返回值要一致
    1. 第一个参数:表示被引用方法的调定者,决定了可以引用哪些类中的方法
      1. 在Stream流当中,第一个参数一般都表示流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类的方法
    2. 第二个参数到最后一个参数:跟抽象方法的形参保持一致,如果抽象方法没有第二个参数,说明引用的方法需要是无参的成员方法。
  4. 被引用方法的功能需要满足当前的需求

如:
上面的抽象方法apply的形参是String类型,且只有一个,决定了只能引用String
类中的无参方法,还要满足需求,就只有toUpperCase这个方法
image.png

这种使用类名引用的局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。


引用数组的构造方法

格式:数据类型[ ] : :new
如:int [ ] : : new

练习:
image.png

ArrayList<Integer>list=new ArrayList<>();
Collections.addAll(list,1,2,3);
//普通表示
/*Integer[] arr = list.stream().toArray(value -> new Integer[value]);System.out.println(Arrays.toString(arr));*///方法引用
Integer[] arr = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));//[1, 2, 3]

总结:
Snipaste_2024-02-03_13-10-52.png

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

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

相关文章

Java SWT Composite 绘画

Java SWT Composite 绘画 1 Java SWT2 Java 图形框架 AWT、Swing、SWT、JavaFX2.1 Java AWT (Abstract Window Toolkit)2.2 Java Swing2.3 Java SWT (Standard Widget Toolkit)2.4 Java JavaFX 3 比较和总结 1 Java SWT Java SWT&#xff08;Standard Widget Toolkit&#xff…

02 使用jdk运行第一个java程序:HelloWorld

使用jdk运行第一个java程序 1 HelloWorld小案例1.1 编写流程1.2 错误示例 首先在CMD命令行里面&#xff0c;使用javac xxxx.java&#xff0c; 进行编译&#xff0c;其中会有报错&#xff1b; 然后生成xxxx.class 文件&#xff0c;然后使用java xxxx.class 进行运行。 1 HelloWo…

瑞_23种设计模式_抽象工厂模式

文章目录 1 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;1.1 概念1.2 介绍1.3 小结1.4 结构 2 案例一2.1 案例需求2.2 代码实现 3 案例二3.1 需求3.2 实现 4 总结4.1 抽象工厂模式优缺点4.2 抽象工厂模式使用场景4.3 抽象工厂模式VS工厂方法模式4.4 抽象工厂…

node.js基础--01

Author nodes&#xff1a;&#xff08;题记&#xff09; node.js is an open-source&#xff0c;cross-platform JAVAScript runtime environment。 node.js是一个开源&#xff0c;跨平台的js运行环境 common commands&#xff08;常用指令&#xff09; 1、C: enter hard …

javaScript的序列化与反序列化

render函数的基本实现 javaScript的序列化与反序列化 一&#xff0c;js中的序列化二&#xff0c;序列化三&#xff0c;反序列化四&#xff0c;总结 一&#xff0c;js中的序列化 js中序列化就是对象转换成json格式的字符串&#xff0c;使用JSON对象的stringify方法&#xff0c;…

新书速览|Python数据科学应用从入门到精通

系统教授数据科学与Python实战&#xff0c;涵盖线性回归、逻辑回归、决策树、随机森林、神经网 本书内容 随着数据存储、数据处理等大数据技术的快速发展&#xff0c;数据科学在各行各业得到广泛的应用。数据清洗、特征工程、数据可视化、数据挖掘与建模等已成为高校师生和职场…

STL——空间配置器

空间配置器是STL六大组件之一&#xff0c;它和其他五个组件相互配合&#xff0c;起着很关键的作用。 容器&#xff1a;各种数据结构、如vector、list、stack、deque、queue、set、map、unordered_map等等算法&#xff1a;各种算法&#xff0c;如sort、serach、copy、erase 提供…

C#用正则表达式验证格式:电话号码、密码、邮编、手机号码、身份证、指定的小数点后位数、有效月、有效日

正则表达式在程序设计中有着重要的位置&#xff0c;经常被用于处理字符串信息。 用Regex类的IsMatch方法&#xff0c;使用正则表达式可以验证电话号码是否合法。 一、涉及到的知识点 Regex类的IsMatch方法用于指示正则表达式使用pattern参数中指定的正则表达式是否在输入字符串…

计算机网络_1.6.2 计算机网络体系结构分层的必要性

1.6.2 计算机网络体系结构分层的必要性 一、五层原理体系结构每层各自主要解决什么问题1、物理层2、数据链路层3、网络层4、运输层5、应用层 二、总结三、练习 笔记来源&#xff1a; B站 《深入浅出计算机网络》课程 本节主要介绍实现计算机网络需要解决哪些问题&#xff1f;以…

这种学习单片机的顺序是否合理?

这种学习单片机的顺序是否合理&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01…

随着网络的快速发展,网络安全问题也日益凸显,遇到攻击该如何处理,如何抉择合适的防护方案

DexunCloud 经过研究发现当今世界&#xff0c;随着网络的快速发展&#xff0c;网络安全问题也日益凸显。其中&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击被认为是网络安全领域里最为严重的威胁之一。毫无疑问&#xff0c;DDoS攻击不仅可以导致网络服务中断&am…

支付宝直连商户处理支付交易投诉管理,支持多商户

大家好&#xff0c;我是小悟 1、问题背景 玩过支付宝生态的&#xff0c;或许就有这种感受&#xff0c;如果收到投诉单&#xff0c;不会通知到手机端&#xff0c;只会在支付宝商家后台-账号中心-安全中心-消费者投诉-支付交易投诉那里显示。那你能一直盯着电脑看吗&#xff1f;…

Flink CEP(基本概念)

Flink CEP 在Flink的学习过程中&#xff0c;我们已经掌握了从基本原理和核心层的DataStream API到底层的处理函数&#xff0c;再到应用层的Table API和SQL的各种手段&#xff0c;可以应对实际应用开发的各种需求。然而&#xff0c;在实际应用中&#xff0c;还有一类更为复…

AI Partition(银灿U盘分区工具)V2.0.0.3

AI Partition(银灿U盘分区工具)V2.0.0.3.zip 复制链接下载吧 https://url20.ctfile.com/f/36743220-1017367709-67f1b9?p2024 (访问密码: 2024) 支持IS903B IS902E IS916 AI Partition(银灿U盘分区量产工具) 这个是银灿官方发布的最新版U盘分区工具&#xff0c;版本号V2.0.0…

翻转二叉树

226. 翻转二叉树 已解答 简单 相关标签 相关企业 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a…

从零学习Linux操作系统 第二十五部分 文本处理工具

一、grep命令的基本使用方法及常用参数介绍 grep [全称&#xff1a;Globally search a Regular Expression and Print 全局搜索正则表达式并打印 ] grep 命令格式 grep 匹配条件 处理文件 grep root passwd过滤root关键字grep -i root passwd后略大小写grep -E “<root”…

嵌入式中物联网核心技术有哪些

IoT军事技术 物联网军事技术是一项利用IoT感知技术在军事活动中获取人、装备、作战环境状态的信息特征&#xff0c;从而实现在军事活动中做出智能化决策和控制局势的军事方针。 据悉&#xff0c;早于2012年10月军方联合了社会研究机构合力创建了“军事物联网联合实验室”。 …

C++核心deque容器,stack容器,queue容器,list容器,set容器,pair ,map容器

3.deque容器 1.deque容器的基本概念 Vector容器是单向开口的连续内存空间&#xff0c;deque则是一种双向开口的连续线性空间。所谓的双向开口&#xff0c;意思是可以在头尾两端插入元素&#xff0c;但是在其头部操作效率奇差&#xff0c;无法被接受。 deque容器和vector容器最…

C++类和对象入门(二)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、类的作用域 类定义了一个新的作用域&#xff0c;类的所有成员都在类的作用域中。在类体外定义成员时&#xff0c;需要…

vue3快速入门

文章目录 1. Vue3简介1.1. 性能的提升1.2.源码的升级1.3. 拥抱TypeScript1.4. 新的特性 2. 创建Vue3工程2.1. 基于 vue-cli 创建2.2. 基于 vite 创建&#xff08;推荐&#xff09;vite介绍创建步骤项目结构安装插件项目结构总结 2.3. 一个简单的效果Person.vueApp.vue 3. Vue3核…