【JAVA入门】Day35 - 方法引用

2024-09-08 04:04
文章标签 java 方法 入门 引用 day35

本文主要是介绍【JAVA入门】Day35 - 方法引用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【JAVA入门】Day35 - 方法引用


文章目录

  • 【JAVA入门】Day35 - 方法引用
    • 一、方法引用的分类
      • 1.引用静态方法
      • 2.引用成员方法
        • 2.1 引用其他类的成员方法
        • 2.2 引用本类和父类的成员方法
        • 2.3 引用构造方法
        • 2.4 使用类名引用成员方法
        • 2.5 引用数组的构造方法
    • 二、方法引用的例题


        方法引用就是“把已经有的方法当作函数式接口中抽象方法的方法体”来使用。

        下面是一个排序方法,它的第二个参数是一个 Comparator 接口的实现类,它是一个函数式接口,因此我们可以用方法引用改写这段代码。

Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}
});

        直接将已经存在的方法作为第二个参数。

public int subtraction(int n1, int n2) {return n2 - n1;
}Arrays.sort(arr, 比较规则 );

        要使用方法引用有一些限制:

  • 最重要的限制是,引用处必须是一个函数式接口,是可以把接口实现类作为参数传递的。
  • 对于被引用的方法有以下三个限制:
    1.被引用的方法必须已经存在了。
    2.被引用的方法的形参返回值需要跟抽象方法保持一致。
    3.被引用的方法的功能要满足当前需求。

        以下面这段代码为例,我们将演示方法引用相较于之前方法的简洁性。

package Functions;import java.util.Arrays;
import java.util.Comparator;public class FunctionDemo1 {public static void main(String[] args) {//需求:创建一个数组,进行倒序排序Integer[] arr = {3,5,4,1,6,2};//匿名内部类Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});//lambda表达式Arrays.sort(arr, (Integer o1, Integer o2) -> {return o2 - o1;});//lambda表达式简化格式Arrays.sort(arr, (o1, o2) -> o2 - o1);//方法引用//表示引用FunctionDemo1类里面的subtraction方法//把这个方法当作抽象方法的方法体Arrays.sort(arr, FunctionDemo1::subtraction);System.out.println(Arrays.toString(arr));}//被引用的方法可以是Java已经写好的,也可以是一些第三方工具类public static int subtraction(int num1, int num2) {return num2 - num1;}
}

一、方法引用的分类

        方法引用一般就分为三大类:引用静态方法、引用成员方法(这个分为引用其他类的成员方法、引用本类的成员方法、引用父类的成员方法)、引用构造方法。但是也有其他调用方式,比如:使用类名引用成员方法、引用数组的构造方法。

1.引用静态方法

格式:

类名::静态方法

范例:

Integer::parseInt

【练习】集合中有“1”“2”“3”“4”“5”五个字符串数字,要求把他们变成 int 类型。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;public class FunctionDemo2 {public static void main(String[] args) {/*集合中有“1”“2”“3”“4”“5”五个字符串数字,要求把他们变成 int 类型。*///1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "1","2","3","4","5");//2.常规方式ArrayList<Integer> list2 = new ArrayList<>();for (String s : list) {int i = Integer.parseInt(s);list2.add(i);}//3.方法引用
/*        list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).forEach(s -> System.out.println(s));*///1.方法需要已经存在//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//3.方法的功能需要把形参的字符串转换成整数//引用的是Integer方法中的pareInt()方法list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));}
}

2.引用成员方法

格式:

对象::成员方法

① 其他类:

其他类对象::方法名

② 本类:

this::方法名

③ 父类:

super::方法名
2.1 引用其他类的成员方法
package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;public class FunctionDemo3 {public static void main(String[] args) {/*只要以张开头的,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据//完整写法
/*        list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s -> System.out.println(s));*///方法引用写法//引用其他类的成员方法//已知有另一个类StringOperation中有同样功能方法//成员方法需要创建对象来使用,因此要先创建StringOperation类对象StringOperation so = new StringOperation();list.stream().filter(so::stringJudge);}
}
2.2 引用本类和父类的成员方法

        要注意,要引用本类成员方法时,若引用处位于 main() 方法中,它是一个静态方法,静态方法是没有 this 和 super 变量的,因此这里就只能先创建好本类的对象再进行调用。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;public class FunctionDemo3 {public static void main(String[] args) {/*只要以张开头的,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据//完整写法
/*        list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s -> System.out.println(s));*///方法引用写法//引用本类的成员方法//已知本类中有同样功能方法//成员方法需要创建对象来使用,因此要先创建本类对象list.stream().filter(new FunctionDemo3()::stringJudge);}public boolean stringJudge(String s) {return s.startsWith("张") && s.length() == 3;}
}

        因此,想要使用 this 和 super,就要在一个非静态方法中,如下面的例子:
        下面的例子中,我们创建了一个窗体,自己在本类中写了一个按钮的事件监听方法,并作为参数传给了按钮的addActionListener()方法,这里就是使用了本类的方法引用,这样做使得该窗体无需实现 ActionListener 接口也能自己实现按钮点击的事件逻辑。

package Functions;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;public class LoginJFrame extends JFrame {//创建一个按钮,点击按钮打印一句话JButton go = new JButton("Go");public LoginJFrame() {//初始化界面initJFrame();//添加组件initView();//显示界面this.setVisible(true);}//设置界面public void initJFrame() {//设置宽高this.setSize(400,500);}//添加组件public void initView() {go.setBounds(120,274,150,50);this.getContentPane().add(go);//给按钮添加点击事件//该方法形参是一个函数式接口//因此可以在此处使用方法引用//此时在本类可以自己写一个按钮监听的方法操作,作为方法引用,使用this::method传入//这样可以使得该窗体不必实现ActionListener接口也能实现按钮的点击事件go.addActionListener(this::method);}//自己写的按钮监听方法public void method(ActionEvent e){Object obj = e.getSource();if(obj == go){System.out.println("go按钮被点击了");}}
}

        下面的例子中,我们让一个窗体继承了一个 MyJFrame 类,再让 MyJFrame 类继承自 JFrame,然后我们在 MyJFrame 类中自己编写了一个事件监听方法 method,然后在 MyJFrame 类中让按钮的 addActionListener() 方法引用 MyJFrame 类中的事件监听方法 method,这样就实现了引用自父类的成员方法。

父类 MyJFrame:

package Functions;import javax.swing.*;
import java.awt.event.ActionEvent;//注意形参和原方法保持一致
public class MyJFrame extends JFrame {public void method(ActionEvent e){System.out.println("go按钮被点击了");}
}

子类 LoginJFrame:

package Functions;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;public class LoginJFrame extends MyJFrame {//创建一个按钮,点击按钮打印一句话JButton go = new JButton("Go");public LoginJFrame() {//初始化界面initJFrame();//添加组件initView();//显示界面this.setVisible(true);}//设置界面public void initJFrame() {//设置宽高this.setSize(400,500);}//添加组件public void initView() {go.setBounds(120,274,150,50);this.getContentPane().add(go);//给按钮添加点击事件//该方法形参是一个函数式接口//因此可以在此处使用方法引用//此时在父类可以自己写一个按钮监听的方法操作,作为方法引用,使用super::method传入go.addActionListener(super::method);}
}

        由上面的例子可以看出,方法引用可以代替函数式接口作为方法的参数传递,利用方法引用可以调整代码结构,省去实现多余的接口。

2.3 引用构造方法

        我们引用构造方法就是为了创建对象。

格式:

类名::new

范例:

Student::new

        以下面的例子为讲解,我们为什么要引用构造方法。
        首先我们在 Student 类中重载了一个构造方法,它是为了适配构造方法引用而设的。

package Functions;import java.util.Objects;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}//用方法引用,在Student类中重载构造方法,按照上面的public Student apply(String s)的方法体重写//str表示流里面的每一个数据public Student(String str){this.name = str.split("-")[0];this.age = Integer.parseInt(str.split("-")[1]);}}

        然后我们在测试类中引用构造方法,代替了原来的 map 方法中的函数式接口重写的方法 apply。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;public class FunctionDemo4 {/*集合里存储姓名和年龄,比如:张无忌,15要求:将数据封装成Student对象并收集到List集合中*/public static void main(String[] args) {//1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41");//3.封装成Student对象并收集到List集合中//String --> Student/*        //用map方法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());*///用方法引用,在Student类中重载构造方法,按照上面的public Student apply(String s)的方法参数和功能重写//构造方法没有返回值,只要保证重载的构造方法对象和你原方法返回的对象保持一致即可List<Student> newList = list.stream().map(Student::new).collect(Collectors.toList());}
}

        这里要注意的就是,构造方法生成的对象,要和原来方法你要求返回的对象一致(姓名、年龄的格式),且构造方法的参数必须和原方法保持一致(String s)。

2.4 使用类名引用成员方法

        直接用类名引用成员方法。
格式:

类名::成员方法

范例:

String::substring

【练习】集合里有一些字符串,要求变成大写后进行输出。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;public class FunctionDemo5 {public static void main(String[] args) {/*集合里有一些字符串,要求变成大写后进行输出。类名::成员方法规则:1.需要有函数式接口2.被引用的方法必须已经存在3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致4.被引用的方法功能要满足当前需求抽象方法形参的详解:第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法(比如第一个参数是String类型,那么只能引用String类中的方法)在Stream流当中,第一个参数一般都表示流里面的每一个数据假设流里面的数据是字符串,那么使用这种方式进行方法调用,只能引用String这个类中的方法第二个参数到最后一个参数:跟被引用的方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");//3.变成大写//String --> String
/*        list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).forEach(s -> System.out.println(s));*///拿流里面的每一个数据,去调用String类中的toUpperCase()方法,方法的返回值就是转换之后的字符串list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));}
}

这种方法有一定的局限性:

1.它不能引用所有类中的成员方法。
2.它能引用的类中的成员方法,取决于它的抽象方法(上面代码中的 apply(String s))的第一个参数类型,这个参数是什么类型,它就只能引用这个类中的方法。
3.如果这个抽象方法(apply(String s))没有第二个及以后的参数,那么它就可以引用一个类中的空参方法。

2.5 引用数组的构造方法

格式:

数据类型[]::new

范例:

Integer[]::new

【练习】集合中存储一些整数,然后收集到数组当中。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.IntFunction;public class FunctionDemo6 {public static void main(String[] args) {/*细节:数组的类型,需要跟流中的数据的类型保持一致*///1.创建集合ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);//2.收集到数组当中
/*        Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});*///此时会将流中每一个数据存入生成的数组中list.stream().toArray(Integer[]::new);}
}

二、方法引用的例题

【练习1】集合中存一些字符串,比如:张三,23。收集到Student数组当中。

package Functions;import JavaStudy1.Array.Array;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;public class FuntcionTest1 {public static void main(String[] args) {/*集合中存一些字符串,比如:张三,23。收集到Student数组当中。*///1.创建集合添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41");//2.先把字符串变成Student对象,然后再把Student对象收集起来//String --> StudentStudent[] arr = list.stream().map(Student::new).collect(Collectors.toList()).toArray(Student[]::new);System.out.println(Arrays.toString(arr));}
}

【练习2】创建集合并添加学生对象,要求获取姓名放到数组中。

package Functions;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class FunctionTest2 {public static void main(String[] args) {/*创建集合并添加学生对象,要求获取姓名放到数组中。"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41"*///1.创建集合添加数据ArrayList<Student> list = new ArrayList<>();Collections.addAll(list, new Student("张无忌",15),new Student("周芷若",14),new Student("赵敏",13),new Student("张强",20),new Student("张三丰",100),new Student("张翠山",40));//2.把姓名获取出来生成字符串数组//Student --> StringString[] arr = list.stream().map(Student::getName).toArray(String[]::new);System.out.println(Arrays.toString(arr));}
}

【练习3】创建集合添加学生对象,把姓名和年龄拼成:张三-23的字符串,并放到数组当中。

package Functions;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class FunctionTest3 {public static void main(String[] args) {/*创建集合添加学生对象,把姓名和年龄拼成:张三-23的字符串,并放到数组当中。*///1.创建集合并添加学生对象ArrayList<Student> list = new ArrayList<>();Collections.addAll(list, new Student("张无忌",15),new Student("周芷若",14),new Student("赵敏",13),new Student("张强",20),new Student("张三丰",100),new Student("张翠山",40));//2.取出姓名和年龄拼成字符串//Student --> StringString[] arr = list.stream().map(Student::toString).toArray(String[]::new);System.out.println(Arrays.toString(arr));}
}

这篇关于【JAVA入门】Day35 - 方法引用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147063

相关文章

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud