# 方法引用

方法引用是把已经有的方法拿过来用 当做函数式接口中抽象方法的方法体

# 引用前提

  1. 引用处必须是函数式接口
  2. 被引用的方法必须存在
  3. 被引用方法的形参和返回值需要跟抽象方法保持一致
  4. 被引用方法的功能要满足当前需求
package methodReference;

import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        //方法引用
//      需求:  创建一个数组,进行倒序排列
        Integer[] arr = {1, 2, 3, 4};

        //匿名内部类
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        System.out.println(Arrays.toString(arr));
        //lambda表达式
        //因为第二个参数Comparator是一个函数式接口 只有函数式接口才可以使用lambda表达式
        Arrays.sort(arr, (o1, o2) -> o2 - o1);
        System.out.println(Arrays.toString(arr));

        //方法引用
//        1. 引用处必须是函数式接口
//        2. 被引用的方法必须存在
//        3. 被引用方法的形参和返回值需要跟抽象方法保持一致
//        4. 被引用方法的功能要满足当前需求
//        ::是方法引用符 存在于方法引用中
        Arrays.sort(arr, Main::subtration);
        System.out.println(Arrays.toString(arr));
    }

    //可以使java已经写好的 也可以是第三方的工具类
    public static int subtration(Integer o1, Integer o2) {
        return o2 - o1;
    }
}

# 方法引用的分类

# 引用静态方法

格式:类名::静态方法 范例:Integer::parseInt

# 引用成员方法

格式: 对象::成员方法

  1. 其他类 其他类对象类名::成员方法名
  2. 本类 this::成员方法名(引用处不能使用静态方法)
  3. 父类 super::成员方法名(引用处不能使用静态方法)

# 技巧

  1. 现在有没有一个方法符合我当前的需求
  2. 如果有这样的方法,那么这个方法是否满足引用的规则
  • 静态: 类名::方法名
  • 成员方法 分本类和其他类
  • 构造方法 类名::new
package MethodReference;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        //引用成员方法
//        需求 集合中有一些名字,按照要求过滤数据
//        数据:“张三","李四","王五","赵六","孙七","周八","吴九","郑十"
//        过滤要求:只要张开头,而且名字是三个字的
        ArrayList<String> listName = new ArrayList<>();
        Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
        //过滤数据
        listName.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(System.out::println);
        //内部类
        listName.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("张") && s.length() == 3;
            }
        }).forEach(System.out::println);
        //方法引用
        //引用其他类的方法
        listName.stream().filter(new StringOperation()::filterFun).forEach(System.out::println);
        //引用本类的方法
        //静态方法中是没有this的 在非静态的方法中才可以使用this
        //在静态方法中可以创建本类的对象进行使用
        listName.stream().filter(new Main()::filterFun).forEach(System.out::println);
    }

    public boolean filterFun(String s) {
        return s.startsWith("张") && s.length() == 3;
    }

}

class StringOperation {
    public boolean filterFun(String s) {
        return s.startsWith("张") && s.length() == 3;
    }
}

# 引用构造方法

为什么要引用构造方法:为了创建对象

package MethodReference;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
    public static void main(String[] args) {

            ArrayList<String> listName = new ArrayList<>();
            Collections.addAll(listName, "张无忌,15", "赵敏,16", "周芷若,17", "周星驰,18", "周星驰,19", "周星驰,20");
            List<StringOperation.Student> collect = listName.stream().map(StringOperation.Student::new).toList();
            System.out.println(collect);

    }
}
class StringOperation extends Main {
    public void StringOperationfilterFunStr(String s) {
        ArrayList<String> listName = new ArrayList<>();
        Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
        //引用父类的方法
        listName.stream().filter(super::filterFunStr).forEach(System.out::println);
    }

    static class Student {
        String name;
        int age;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
       //方法引用参数必须一致
        //在类中可创建形参不同的多个构造方法
        public Student(String str) {
            String[] split = str.split(",");
            this.name = split[0];
            this.age = Integer.parseInt(split[1]);
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

    }
}

# 使用类名引用成员方法

  • 格式:类名::成员方法
  • 范例:String::substringkmd

该引用方法独有的特性 抽象方法形参的详解:

  • 第一个参数:表示被引用方法的调用者,决定了可以引用那些类中的方法
  • stream流当中,第一个参数一般都表示流里面的每一个数据
  • 假设流里面的数据是字符串,那么使用这种方式进行方法引用只能引用String这个类中的方法
  • 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

# 局限性

  • 不能引用所有类中的成员方法
  • 它跟抽象方法中的第一个参数有关,这个参数是什么类型的,就只能引用什么类型中的方法
package MethodReference;
public class Main {
    public static void main(String[] args) {
        //使用类名引用成员方法
//        练习:集合里面一些字符串,要求变成大写后输出
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "abc", "b", "c");
        list.stream().map(new Function<String, String>() {
            //用这种方式进行方法引用只能引用`String`这个类中的方法
            //如果没有第二个参数,说明被引用的方法需要是无参的成员方法
            @Override
            public String apply(String s) {
                return s.toUpperCase();
            }
        }).forEach(System.out::println);
        //拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换之后的结果
        list.stream().map(String::toUpperCase).forEach(System.out::println);
    }
}

# 引用数组的构造方法

  • 格式:数据类型[]::new
  • 范例:int[]::new 必须跟流中的类型一致
package MethodReference;
public class Main {
    public static void main(String[] args) {
        //练习:集合中存储一些整数,收集到一个数组中
        ArrayList<Integer> list1 = new ArrayList<>();
        Collections.addAll(list1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer[] integers = list1.stream().toArray(new IntFunction<Integer[]>() {
            @Override
            public Integer[] apply(int value) {
                return new Integer[value];
            }
        });
        //打印
        System.out.println(Arrays.toString(integers));

        //方法引用简化写法
        Integer[] array = list1.stream().toArray(Integer[]::new);
        System.out.println(Arrays.toString(array));
    }
}

# 方法引用练习

package MethodReference;
public class Main {
    public static void main(String[] args) {
        //练习1:集合中存储一些字符串数据,比如:张三,23 收集到Student类型的数组中
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2, "张三,23", "赵四,24", "孙五,25", "周六,26", "吴七,27", "郑八,28", "吴九,29", "郑十,30");
        StringOperation.Student[] array1 = list2.stream().map(StringOperation.Student::new).toArray(StringOperation.Student[]::new);
        System.out.println(Arrays.toString(array1));

        //练习2:创建集合添加学生对象,对象的属性name、age 只获取姓名添加到数组当中
        ArrayList<StringOperation.Student> listStudent = new ArrayList<>();
        Collections.addAll(listStudent, new StringOperation.Student("张三", 23), new StringOperation.Student("赵四", 24), new StringOperation.Student("孙五", 25));
        String[] array2 = listStudent.stream().map(new StringOperation.Student()::getName).toArray(String[]::new);
        //使用类名引用成员方法
        //在该stream流中类型是StringOperation.Student类型
        //在map的抽象类中无第二个参数 说明需要无参的成员方法
        //StringOperation.Student类中的getName刚好满足
        String[] array4 = listStudent.stream().map(StringOperation.Student::getName).toArray(String[]::new);
        System.out.println(Arrays.toString(array2));
        System.out.println(Arrays.toString(array4));

        //练习3:创建集合添加学生对象,学生对象属性:name、age
//        把姓名和年龄拼接成:张三-23的字符串,并放入数组中
        ArrayList<StringOperation.Student> listStudent1 = new ArrayList<>();
        Collections.addAll(listStudent1, new StringOperation.Student("张三", 23), new StringOperation.Student("赵四", 24), new StringOperation.Student("孙五", 25));
        String[] array3 = listStudent1.stream().map(new StringOperation.Student()::getNameAgeStr).toArray(String[]::new);
        System.out.println(Arrays.toString(array3));
    }
}
class StringOperation extends Main {
    public void StringOperationfilterFunStr(String s) {
        ArrayList<String> listName = new ArrayList<>();
        Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
        //引用父类的方法
        listName.stream().filter(super::filterFunStr).forEach(System.out::println);
    }

    static class Student {
        String name;
        int age;

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

        public Student(String str) {
            String[] split = str.split(",");
            this.name = split[0];
            this.age = Integer.parseInt(split[1]);
        }

        public Student() {

        }

        public String getName() {
            return name;
        }

        public String getName(Student student) {
            return student.name;
        }

        public String getNameAgeStr(Student student) {
            return student.name + "-" + student.age;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }


    }
}

# 引用本类和父类的成员方法

package MethodReference;

import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public boolean filterFunStr(String s) {
        return s.startsWith("张") && s.length() == 3;
    }

    public void filterFun(String s) {
        ArrayList<String> listName = new ArrayList<>();
        Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
        //引用本类的方法
        listName.stream().filter(this::filterFunStr).forEach(System.out::println);
    }
}

class StringOperation extends Main {
    public void StringOperationfilterFunStr(String s) {
        ArrayList<String> listName = new ArrayList<>();
        Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
        //引用父类的方法
        listName.stream().filter(super::filterFunStr).forEach(System.out::println);
    }
}

上次更新: 1/17/2025, 9:38:51 AM