Java——方法的引用

简介: 方法引用允许将已有方法作为函数式接口的实现。使用“::”符号,需具备函数式接口,被引用的方法须存在且参数和返回值需与抽象方法一致。其分类包括:静态方法引用(类::方法名)、成员方法引用(对象::方法名、this::方法名、super::方法名)和构造方法引用(类名::new)。方法引用提高了代码的简洁性和可读性,减少了样板代码。

🍁1. 方法引用

方法的引用:把已经存在的方法拿来使用,当作函数式接口中抽象方法的方法体

" :: "是方法引用符

方法引用时需要注意:

1. 需要有函数式接口

2. 被引用的方法必须存在

3. 被引用的方法的形参和返回值要和抽象方法保持一致

4. 被引用的方法的功能要满足当前的需求

以Arrays中的静态方法 sort() 为例,其中的参数就是一个函数式接口,先来用匿名内部类和lambda的方式演示一下

需求:把数组中的元素降序排列

public class Demo1 {
    public static void main(String[] args) {
        //把数组中的内容倒序排列
        Integer[] arr = {2, 1, 4, 5, 3};
        //匿名内部类的方式
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public 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);
        System.out.println(Arrays.toString(arr));
    }
}

接下来看方法引用的方式

public class Demo1 {
    public static void main(String[] args) {
        //把数组中的内容倒序排列
        Integer[] arr = {2, 1, 4, 5, 3};
        //方法引用
        Arrays.sort(arr, Demo1::subtraction);
        System.out.println(Arrays.toString(arr));
    }
    public static int subtraction(int num1, int num2) {
        return num2 - num1;
    }
}

🍁2. 方法引用的分类

🍁2.1 引用静态方法

格式: 类 :: 方法名

需求:获取集合中的数字部分

如果说使用之前的方法来解决,就是再定义一个集合,在循环中调用parseInt()方法,再把结果添加到新集合中

public class Demo2 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "1", "2", "3", "4");
        //匿名内部类方式
        arrayList.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                int res = Integer.parseInt(s);
                return res;
            }
        }).forEach(s -> System.out.print(s));
        System.out.println();
        //方法引用
        arrayList.stream().map(Integer::parseInt).forEach(s -> System.out.print(s));
    }
}

这里正好符合方法引用的条件

🍁2.2 引用成员方法

格式:

其他类:其他类的对象 :: 方法名

本类中:this :: 方法名

父类中:super :: 方法名

需求:找出集合中以 'a' 开头并且长度大于2的字符串

这里在另一个类中定义了一个专门进行字符串判断的方法,并且参数类型和返回值都和用到的抽象方法一致,这时就可以使用方法引用了

🍁2.3 引用构造方法

格式:类名 :: new

需求:把集合中的字符串封装成Student对象收集到List集合中

public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Student(String s) {
        this.name = s.split(",")[0];
        this.age = Integer.parseInt(s.split(",")[1]);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Demo4 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "张三,23", "李四,21", "王五,21");
        //把集合中的字符串封装成Student对象收集到List集合中
        //之前stream流的写法
        List<Student> list1 = arrayList.stream().map(new Function<String, Student>() {
            @Override
            public Student apply(String s) {
                return new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1]));
            }
        }).collect(Collectors.toList());
        System.out.println(list1);
        //引用构造方法
        List<Student> list2 = arrayList.stream().map(Student::new).collect(Collectors.toList());
        System.out.println(list2);
    }
}

在使用引用构造方法的时候,由于需要保证被引用的方法的形参和返回值要和抽象方法保持一致,所以要重新再写一个符合条件的构造方法才可以

🍁3. 使用类名引用成员方法

这里的规则是要稍微变一下的,在刚开始提到的第三条中 “被引用的方法的形参和返回值要和抽象方法保持一致” 要更改为被引用方法的形参要和抽象方法的第二个参数到最后一个形参保持一致,返回值需要保持一致

对于抽象方法中的形参:第一个参数表示被引用方法的调用者,决定了可以引用哪些类中的方法,在Stream流中,第一个参数一般都表示流里面的每一个数据,如果说流里面的是字符串类型,那么使用这种方式进行方法引用,只能用String这个类中的方法

第二个参数到最后一个参数,需要和引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

public class Demo5 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa", "bbb", "ccc", "ddd");
        //把集合中的字符串变为大写之后进行输出
        arrayList.stream().map(new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s.toUpperCase();
            }
        }).forEach(s -> System.out.print(s + " "));
        System.out.println();
        //方法引用
        arrayList.stream().map(String::toUpperCase).forEach(s -> System.out.print(s + " "));
    }
}

这里抽象方法的方法体只有一个参数,引用的方法需要是无参的成员方法

🍁4. 引用数组的构造方法

引用数组的构造方法就是为了创建一个数组,创建的数组类型要和流中的数据类型保持一致

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

需求:把集合中的数据收集起来放在数组中

public class Demo6 {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        Collections.addAll(arrayList,1,2,3,4,5);
        //匿名内部类方式
        Integer[] array1 = arrayList.stream().toArray(new IntFunction<Integer[]>() {
            @Override
            public Integer[] apply(int value) {
                return new Integer[value];
            }
        });
        System.out.println(Arrays.toString(array1));
        //数组引用构造方法
        Integer[] array2 = arrayList.stream().toArray(Integer[]::new);
        System.out.println(Arrays.toString(array2));
    }
}

🍁5. 方法引用的优点

简洁性:方法引用通常比Lambda表达式更简洁,特别是当Lambda表达式只是简单地调用一个已存在的方法时。

可读性:对于熟悉的方法名,方法引用比Lambda表达式更容易理解。

减少样本模板:方法引用减少了编写Lambda表达式时的样板代码,使代码更加清晰。


相关文章
|
27天前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
69 9
|
26天前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
37 4
|
26天前
|
Java
深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
26 4
|
23天前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
25 1
|
2月前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
51 17
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
117 4
|
1月前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
165 2
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
27 3
|
2月前
|
Java 大数据 API
别死脑筋,赶紧学起来!Java之Steam() API 常用方法使用,让开发简单起来!
分享Java Stream API的常用方法,让开发更简单。涵盖filter、map、sorted等操作,提高代码效率与可读性。关注公众号,了解更多技术内容。