Java8新特性之四大内置核心函数式接口以及方法引用

在了解了Lambda表达式后,发现它适用于函数式接口,Java8内置了许多函数式接口,而为了使Lambda表达式在某些情况下能够更为精简,就出现了方法引用这一新特性,接下来分别看看这两个新特性

四大内置核心函数式接口:
所谓函数式接口,指的是接口中只含有一个抽象方法的接口,用@FunctionalInterface注解可以对该接口进行检验,为了配合lambda表达式使用,java8内置了四大核心函数式接口,分别是:
Consumer:消费型接口
正如其名,消费,该接口中有一个不带返回值带一个参数的方法accept

 void accept(T t)

Supplier:供给型接口
供给,该接口中有一个带返回值不带参数的方法get

 T get();

Function<T,R>:函数型接口
其中接口中的泛型T代表参数,R代表返回值,该接口有一个带返回值并且带一个参数的方法apply

R apply(T t);

Predicate:断言型接口
该接口有一个返回值为boolean类型且带一个参数的方法test

boolean test(T t);

除这四大接口外,还有许多由其衍生出来接口,比如BiPredicate<T, U>(返回值为boolean且有两个参数)、BiFunction<T, U, R>(返回值为R且有两个参数)等等

那么说完核心概念,我们分别看一看结合lambda表达式,这四个函数型接口能够做一些什么
例子一:消费型接口,这里就以消费为例,happy()为消费的方法,参数为消费的金额money以及用于消费的函数型接口Consumer:

  @Test
    public void test1(){
        happy(10000,(m)-> System.out.println("消费了"+m+"元"));
    }
    public void happy(double money, Consumer<Double> con){
        con.accept(money);
    }

可以看到lambda表达式能够作为参数传入方法中。

例子二:供给型接口

//功能:产生指定个数的整数并且存入集合中
@Test
    public void test2(){
        List<Integer> nums=getNumList(10,()->(int)(Math.random()*100));
        for (Integer integer:nums) {
            System.out.println(integer);
        }
    }
    public List<Integer> getNumList(int num, Supplier<Integer> sup){
        List<Integer> list=new ArrayList<>();
        for (int i=0;i<num;i++){
            Integer n=sup.get();
            list.add(n);
        }
        return list;
    }

例子三:函数型接口

//功能:处理字符串
@Test
    public void  test3(){
        String newStr=strHandler("\t\t hello world",(str)->str.trim());
        System.out.println(newStr);
        String str2=strHandler("hello world",(str)->str.substring(0,3));
        System.out.println(str2);
    }
    public String strHandler(String str,Function<String,String> fun){
        return fun.apply(str);
    }

例子四:断言型接口

@Test
    public void test4(){
        List<String> list= Arrays.asList("Hello","World","Lambda","OK");
        List<String> strList=filterStr(list,(s)->s.length()>3);
        for (String str : strList) {
            System.out.println(str);
        }
    }
    //功能:将满足条件的字符串添加到集合中
    public List<String> filterStr(List<String> strings, Predicate<String> pre){
        List<String> strings=new ArrayList<>();
        for (String str:strings) {
            if (pre.test(str)){
                list.add(str);
            }
        }
        return list;
    }

不难看出,在结合了Lambda表达式以及函数型接口的使用后,我们能够使用更少的代码完成传统代码所能够实现的功能
接下来我们说一说方法引用,所谓方法引用,指的是若Lambda体中有方法已经实现了,那么便可使用,标志符号是“::”,这是Lambda表达式的另一种表现形式,它主要有三种语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
第三种语法格式需在特定的条件下才可使用,我们在接下来的代码里进行演示
首先是对象::实例方法名,我们使用consumer接口示例,比如我们现在要输出一个语句,之前的写法:

@Test
    public void  test1(){
        Consumer<String> consumer=(x) -> System.out.println(x);
        consumer.accept("语法格式1");
    }

这里我们输出了一句“语法格式1”,由于println方法在lambda体中已经使用过一次,查看System.out的源码:

public final static PrintStream out = null;

发现它其实是打印流PrintStream对象,为了方便理解,我们使用方法引用可以这样写:

@Test
    public void  test1(){
        PrintStream ps=System.out;
        Consumer<String> consumer=(x) -> ps.println(x);
        consumer.accept("语法格式1");
        Consumer<String> con=ps::println;
        con.accept("对象::实例方法名");

    }

再还原成我们常用的方式:

@Test
    public void  test1(){

        Consumer<String> consumer=(x) -> System.out.println(x);
        consumer.accept("语法格式1");
        Consumer<String> con=System.out::println;
        con.accept("对象::实例方法名");

    }

接下来是第二种语法格式类::静态方法名,我们使用comparator接口进行示例,比如我们要比较两个整数:

 @Test
    public void test2(){
        Comparator<Integer> com=(x,y) ->Integer.compare(x,y);
        System.out.println(com.compare(2,1));
    }

而使用方法引用,我们可以这样写:

 @Test
    public void test2(){
        Comparator<Integer> com=(x,y) ->Integer.compare(x,y);
        System.out.println(com.compare(2,1));
        Comparator<Integer> com1=Integer::compare;
        System.out.println(com1.compare(1,2));
    }

接下来是第三种格式类::实例方法名,该格式比较特殊,比如我们现在需要比较两个字符串是否相等,使用我们之前提到的BiPredicate接口:

 @Test
    public void test3(){
        BiPredicate<String,String> bp=(x,y) ->x.equals(y);
    }

在这里x是.equals方法的调用者,而y是作为.equals方法的参数,在这种情况下,我们可以这样写:

 @Test
    public void test3(){
        BiPredicate<String,String> bp=(x,y) ->x.equals(y);
        BiPredicate<String,String> bp1=String::equals;
    }

所以得出结论,这种类::实例方法名的格式的使用条件是,当Lambda参数列表的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,方可使用该方法
而有了方法引用,类似地,我们还可以使用构造器引用,比如我们有一个student对象,其中有有许多构造方法:

public class Student implements Serializable {
    Integer id;
    String name;
    Integer age;
    Double height;

    public Student() {
    }

    public Student(Integer id) {
        this.id = id;
    }

    public Student(Integer id, Integer age) {
        this.id = id;
        this.age = age;
    }

    public Student(Integer id, String name, Integer age, Double height) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getHeight() {
        return height;
    }

    public void setHeight(Double height) {
        this.height = height;
    }
}

例子:使用构造器引用新建一个Student对象,我们可以这样新建:

@Test
    public void test5(){
        Function<Integer,Student> fun=(x)->new Student(x);
        Student student1=fun.apply(101);
        System.out.println(JSONObject.toJSON(student1));
    }

我们使用只带一个参数id的构造方法新建一个student对象,运行结果如下:
在这里插入图片描述
使用构造器引用,如下:

@Test
    public void test5(){
        Function<Integer,Student> fun=(x)->new Student(x);
        Student student1=fun.apply(101);
        System.out.println(JSONObject.toJSON(student1));
        Function<Integer,Student> fun2=Student::new;
        Student student2=fun2.apply(101);
        System.out.println(JSONObject.toJSON(student2));
    }

运行结果如下:
在这里插入图片描述
同样的,我们还可以使用数组引用,格式也是类似,比方我们新建一个String类型的数组并打印其长度:

@Test
    //数组引用
    public void test7(){
        Function<Integer, String[]> fun=(x)->new String[x];
        String[] strings=fun.apply(10);
        System.out.println(strings.length);
        Function<Integer,String[]> fun2=String[]::new;
        String[] strings1=fun2.apply(12);
        System.out.println(strings1.length);
    }

运行结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值