jdk8 新特性之 函数式接口

一、函数式接口说明

1、函数式接口条件

(1)、只包含一个抽象方法的接口,称为函数式接口。

(2)、你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。

(3)、我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

2、@FunctionalInterface 注解说明

  • 1.此注解表明该接口是一个函数式接口,所谓的函数式接口,是指“有且只有一个抽象方法”
  • 2.接口中的静态方法,默认方法(default修饰),以及java.lang.Object类中的方法都不算抽象方法。
  • 3.如果接口符合函数式接口的定义,则此注解加不加无所谓,加了会方便编译器检查。如果不符合函数式接口定义,则此注解会报错。

函数式接口其实是继承于Object的。

3、Lambda 简写/省略规则

示例:
该示例来自第二步骤

// 简写前
(Integer t) -> { return t * 2; };

// 简写后
t ->  t * 2;

简写:
1、传入参数可以省略类型,如: (t) -> { return t * 2; };
2、传入参数如果只有一个,可以省略括号,如: t -> { return t * 2; };
3、返回参数没有复杂业务,一行代码可完成逻辑,可以省略 大括号+分号+ return,如: t -> { t * 2 };

缺点:
当然,Lambda表达式虽然简洁,也是有缺点的:就是降低了代码的可读性,比如一眼看不出来原来的函数式接口是什么。所以什么情况用Lambda,要多写多练才会用的恰当。

4、使用函数式接口及 Lambda 创建一个线程

// 创建线程
new Thread(() -> {
     // 业务逻辑
     System.out.println("666");
}).start();

 // 简单业务逻辑--可简写为
 new Thread(() -> System.out.println("666")).start();

可以看出 Runnable 接口是一个函数式接口,可以使用Lambda 来创建异步线程
在这里插入图片描述

5、四大内置函数式接口(+其他)

只包含一个抽象方法的接口,称为函数式接口。
可以通过 Lambda 表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在任意函数式接口上使用@FunctionalInterfaceFunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

在这里插入图片描述
其他接口
在这里插入图片描述

二、函数式接口创建

1、创建函数式接口

@FunctionalInterface
interface Fun3 {
    // 抽象方法,必须只有一个
    Integer run(Integer num);
}

2、使用

(t) -> t * 2 为使用run方法实现,()中的为传递的参数,-> 后的为run 方法的实现逻辑( t * 2 )

class Test3 {
    // TODO  测试
    public static void main(String[] args) {
        Fun3 fun3 = (t) -> t * 2;
        // 调用刚定义的实现逻辑
        Integer num = fun3.run(5);
        System.out.println("n * 2 = " + num);   // 输出10
   }
}


// 简写: Fun3 fun3 = (t) -> t * 2; --> 完整写法: Fun3 fun4 = (t) -> { return t * 2; };

三、创建类似于 forEach 的函数式接口 (函数式接口作为参数)

1、创建函数式接口

@FunctionalInterface
interface Fun<T> {
    void run(T t);
}


/**
 * TODO  创建类,使用函数式接口作为参数,并调用函数式接口中的 run 方法
 */
class FunClass {
    public <T> void forEach(List<T> list, Fun fun) {
        for (T t : list) {
            fun.run(t);
        }
    }
}

2、使用

(t) = run(T t) 的参数 t, 调用时 (t) 可任意命名, 但实际参数内容等于 run(T t) 的参数的 t

class Test {
    // TODO  测试
    public static void main(String[] args) {
    
        ArrayList<String> lists = new ArrayList<>();
        lists.add("665");
        lists.add("666");
        lists.add("667");
       
        // 使用
        new FunClass().forEach(lists, (t) -> {
            System.out.println(t);
        });        

        // 省略写法
        new FunClass().forEach(lists, t -> System.out.println(t));

        // 继续省略写法
        new FunClass().forEach(lists, System.out::println);
        
        // 输出 
        // 665  
        // 666  
        // 667
    }
}

四、使用函数式接口进行参数转换 (固定参数类型)

1、创建函数式接口

@FunctionalInterface
interface FunConverter2<F, T> {

    //加 - 使用static 关键字默认实现的方法不算抽象方法。
    static double add(int a, int b) {
        return a + b;
    }

    //减 - default 关键字默认实现的方法不算抽象方法。
    default double subtract(int a, int b) {
        return a - b;
    }

    // 抽象方法,必须只有一个,该抽象方法传入F 类型的数据,返回T类型的数据
    T convert(F from);

}

2、使用

class FunConverterTest {
    // TODO  测试
    public static void main(String[] args) {

        // 将传入的String-from,转为Integer
        FunConverter2<String, Integer> converter = (from) -> Integer.valueOf(from);
        Integer converted = converter.convert("123");
        System.out.println(converted); // 123 整型

        // 将传入的Integer-from,转为 String
        FunConverter2<Integer, String> converter2 = (from) -> String.valueOf(from);
        String converted2 = converter2.convert(123);
        System.out.println(converted2); // 123 字符串

        // 将获取传入值的2次方
        FunConverter2<Integer, Integer> converter3 = (from) -> from * from;
        Integer converted3 = converter3.convert(2);
        System.out.println(converted3); // 4

        // 将传入字符串转为小写
        FunConverter2<String, String> converter4 = (from) -> from.toLowerCase();
        String converted4 = converter4.convert("ABC");
        System.out.println(converted4); // abc

        // 将传入字符串转为大写
        FunConverter2<String, String> converter5 = (from) -> from.toUpperCase();
        String converted5 = converter5.convert("abc");
        System.out.println(converted5); // ABC
    }
}

五、使用四大接口之–函数型接口 Function<T, R> 示例

Function<T, R> 为函数型接口,T 为传入参数类型,R为返回参数类型

package interfaceTest;

import java.util.function.Function;

public class Test4 {


    // 定义一个方法用于对数组求和
    public static Integer getSum(int[] arr) {
        int sum = 0;
        for (int i : arr) {
            sum += i;
        }
        return sum;
    }

    // 表示传入int数组,返回Integer
    public static Integer test(Function<int[], Integer> fun, int[] arr) {
        return fun.apply(arr);
    }
}

class Test5 {
    public static void main(String[] args) {
        // Fun<Consumer<int[]>> consumerFun = Test4::test;
        int[] arr = {1, 2, 4, 5, 6, 2, 3};
        Integer num = Test4.test(Test4::getSum, arr);
        System.out.println(num); // 23
      
        //Function<int[], Integer> fun = Test4::getSum;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值