第32讲 方法引用

1 方法引用

1.1 方法引用简述

Lambda表达式可以使得在调用那些已经拥有方法名的方法的代码更简洁、更容易理解。

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

Lambda表达式简写后:

Arrays.sort(arr, Arrays.sort(arr, ((o1, o2) -> o1 - o1));      

但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作。在这种情况下,我们倾向于通过方法名来调用它。

从Java8开始,我们可以使用方法引用进一步简写。

方法引用就是:把已经存在的方法当作抽象方法的方法体。

方法引用可以理解为Lambda表达式的另外一种表现形式。

假设现已经存在一个做减法的方法,它的形参和返回值和抽象方法compare一致,且本质也是做两个数的减法。

public int subtraction(int n1, int n2) {
    return n1 - n2;
}

我们可以通过方法引用来实现排序。

import java.util.Arrays;

public class sortDemo2 {
    public static void main(String[] args) {
        Integer[] arr = {4, 5, 1, 8, 6, 34, 52, 33, 9, 23};

        //方法引用
        Arrays.sort(arr, sortDemo2::subtraction);

        System.out.println(Arrays.toString(arr));
        // [1, 4, 5, 6, 8, 9, 23, 33, 34, 52]
    }

    //做减法的函数
    public static int subtraction(int n1, int n2) {
        return n1 - n2;
    }
}

1.2 方法引用前提

  • 引用处必须是函数式接口 。上文中的Comparator接口就是函数式接口。
  • 被引用的方法必须已经存在
  • 被引用的方法的形参和返回值必须跟抽象方法保持一致
  • 被引用的方法的功能必须能满足当前的需求

2 引用静态方法

格式: 类名::静态方法

案例: 要把String类型集合中的字符串变成int类型的整数。

使用匿名内部类:

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

public class FunctionDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        list.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);	
            }
        }).forEach(i -> System.out.print(i + " "));	//1 8 22 13 9 
    }
}

使用方法引用简写

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

public class FunctionDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        list.stream()
                .map(Integer::parseInt)
                .forEach(i -> System.out.print(i + " "));	//1 8 22 13 9 
    }
}

3 引用成员方法

引用类格式
本类this::方法名
父类类super::方法名
其他类其他类的对象::方法名

3.1 引用本类

引用处不能是静态方法,因为静态方法中没有 this, super 关键字

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

public class FunctionDemo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        new FunctionDemo3().test(list);	//运行结果: 22 13
    }
    
    public void test(ArrayList<String> list) {
        //引用本类成员方法
        list.stream().filter(this::screen)
                .forEach(s -> System.out.println(s));
    }

    public boolean screen(String s) {
        return s.length() >= 2;
    }
}

3.2 引用父类

引用处不能是静态方法,因为静态方法中没有 this, super 关键字

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

public class FunctionDemo4 extends FunctionDemo4Father {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        new FunctionDemo3().test(list);	//运行结果: 22 13
    }

    public void test(ArrayList<String> list) {
        //引用父类成员方法
        list.stream().filter(super::screen)
                .forEach(s -> System.out.println(s));
    }
}

//父类
class FunctionDemo4Father {
    public boolean screen(String s) {
        return s.length() >= 2;
    }
}

3.3 引用其他类

案例: 筛选出集合中字符串长度大于等于2的字符串。

使用匿名内部类:

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

public class FunctionDemo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() >= 2;
            }
        }).forEach(s -> System.out.println(s));
    }
}

当恰巧有一个类中的一个方法可以满足方法引用的前提时:

//恰巧有StringOperation类中的screen方法可以满足方法引用的前提
public class StringOperation {
    public boolean screen(String s) {
        return s.length() >= 2;
    }
}

使用方法引用简写

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

public class FunctionDemo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "1", "8", "22", "13", "9");

        list.stream().filter(new StringOperation()::screen)
            	.forEach(s -> System.out.println(s));	//运行结果: 22 13
    }
}

4 引用构造方法

格式: 类名::new

案例: 将字符串类型集合中数据封装成Person对象,并添加到List集合中。

采用匿名内部类实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FunctionDemo5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张三-19", "李四五-20", "张五六-18", "王五-22");

        List<Person> personList = list.stream().map(new Function<String, Person>() {
            @Override
            public Person apply(String s) {
                String[] split = s.split("-");
                return new Person(split[0], Integer.parseInt(split[1]));
            }
        }).collect(Collectors.toList());

        System.out.println(personList);	
        //运行结果: [Person{name = 张三, age = 19}, Person{name = 李四五, age = 20}, Person{name = 张五六, age = 18}, Person{name = 王五, age = 22}]
    }
}

//Person类
class Person {
    private String name;
    private int age;
    
    //省略带全参、无参构造,set、get方法
}

采用方法引用实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class FunctionDemo5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张三-19", "李四五-20", "张五六-18", "王五-22");

        List<Person> personList = list.stream()
                .map(Person::new)
                .collect(Collectors.toList());

        System.out.println(personList);
        //运行结果: [Person{name = 张三, age = 19}, Person{name = 李四五, age = 20}, Person{name = 张五六, age = 18}, Person{name = 王五, age = 22}]
    }
}

class Person {
    private String name;
    private int age;

    //在JavaBean类中添加满足方法引用前提的构造方法:
    //	1.被引用的方法的形参和返回值必须跟抽象方法保持一致;
    //	2.被引用的方法的功能必须能满足当前的需求。
    public Person(String listStr) {
        String[] split = listStr.split("-");
        this.name = split[0];
        this.age = Integer.parseInt(split[1]);
    }
    
    //省略带全参、无参构造,set、get方法
}

5 通过类名引用成员方法

5.1 通过类名引用成员方法的前提

  • 引用处必须是函数式接口
  • 被引用的方法必须已经存在
  • 抽象方法的第一个形参决定了可以引用哪些类中的方法
  • 被引用的方法的形参需要跟抽象方法的第二个到最后一个形参保持一致
  • 返回值必须跟抽象方法保持一致
  • 被引用的方法的功能必须能满足当前的需求

抽象方法的形参补充:

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

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

局限性: 抽象方法的第一个参数是什么类型的,就只能引用这个类中的方法,其他类的方法不能引用。

5.2 案例及解读

: 将集合中的字符串转换成大写

采用匿名内部类实现:

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

public class FunctionDemo6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "aaa", "ccc", "eee");

        list.stream().map(new Function<String, String>() {
            @Override
            public String apply(String s) {
                return s.toUpperCase();
            }
        }).forEach(s -> System.out.println(s));
    }
}

采用方法引用实现:

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

public class FunctionDemo6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "aaa", "ccc", "eee");

        list.stream()
                .map(String::toUpperCase)
                .forEach(s -> System.out.println(s));
    }
}

解释: Function 接口中的 apply 方法没有第二个参数,说明被引用的方法需要是无参的成员方法。而 String 类中的方法 toUpperCase 是无参的,且与 apply 方法的返回值一致。

public String toUpperCase() {
    return toUpperCase(Locale.getDefault());
}

map(String::toUpperCase) 可以理解为:让流中的每一个数据去调用 String 中的 toUpperCase 方法,该方法的返回值就是转换后的结果。

6 引用数组的构造方法

格式: 数据类型[]::new //创建一个该数据类型的数组

案例: 将集合中的整数收集到数组当中。

采用匿名内部类实现:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;

public class FunctionDemo7 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list, 1, 3, 5, 2, 4);

        Integer[] array = list.stream().toArray(new IntFunction<Integer[]>() {
            @Override
            public Integer[] apply(int value) {
                return new Integer[value];
            }
        });

        System.out.println(Arrays.toString(array));	//[1, 3, 5, 2, 4]
    }
}

采用方法引用实现:

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

public class FunctionDemo7 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list, 1, 3, 5, 2, 4);

        //会自动创建一个Integer类型的,长度与集合长度一致的数组。
        Integer[] array = list.stream().toArray(Integer[]::new);
        
        System.out.println(Arrays.toString(array));	//[1, 3, 5, 2, 4]
    }
}

7 综合应用

1.集合中存储字符串:如”张三,23“。将数据收集到Student类型的数组当中。

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

public class FunctionDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张三,23", "李四,24", "王五,26");

        Student[] studentArr = list.stream()
                .map(Student::new)
                .toArray(Student[]::new);

        System.out.println(Arrays.toString(studentArr));
        //[Student{name = 张三, age = 23}, Student{name = 李四, age = 24}, Student{name = 王五, age = 26}]
    }
}

class Student {
    private String name;
    private int age;

    public Person(String listStr) {
        this.name = listStr.split(",")[0];
        this.age = Integer.parseInt(listStr.split(",")[1]);
    }
    
    //省略带全参、无参构造,set、get方法
}

2.创建集合添加学生对象,学生对象属性:name,age。只获取姓名放到数组当中。

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

public class FunctionDemo2 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("李四", 24);
        Student s3 = new Student("王五", 26);
        Collections.addAll(list, s1, s2, s3);

        String[] stringArr = list.stream()
                .map(Student::getName)
                .toArray(String[]::new);

        System.out.println(Arrays.toString(stringArr)); //[张三, 李四, 王五]
    }
}

class Student {
    private String name;
    private int age;

    //省略带全参、无参构造,set、部分get方法
    
    public String getName() {
        return name;
    }
}

3.创建集合添加学生对象,学生对象属性:name,age。将姓名年龄拼接成:”张三-23“的字符串,放到数组中

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

public class FunctionDemo3 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("李四", 24);
        Student s3 = new Student("王五", 26);
        Collections.addAll(list, s1, s2, s3);

        String[] stringArr = list.stream()
                .map(s -> s.getName() + "-" + s.getAge())
                .toArray(String[]::new);

        System.out.println(Arrays.toString(stringArr)); //[张三-23, 李四-24, 王五-26]
    }
}

class Student {
    private String name;
    private int age;
    
    //省略带全参、无参构造,set、get方法
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值