A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

    今天我们来学习几个常见的函数式接口。
   以下是今天的学习目标:
  • 能够使用@FunctionalInterface注解
  • 能够理解Lambda延迟执行的特点
  • 能够使用Lambda作为方法的参数
  • 能够使用Lambda作为方法的返回值
  • 能够使用Supplier<T>函数式接口
  • 能够使用Consumer<T>函数式接口
  • 能够使用Predicate<T>函数式接口
  • 能够使用Function<T, R>函数式接口


以下是今天的详细笔记:
函数式接口
函数式接口概念, 自定义函数式接口
函数式接口: JDK 8 新特性
    有且仅有一个抽象方法的接口, 适用于函数式编程场景的接口
    (默认方法, 静态方法, 私有方法, 与java.lang.Object类中定义相同的抽象方法, 都不算作抽象方法)
自定义函数式接口:
        接口中有且只有一个抽象方法
@FunctionalInterface的作用:
        在接口上使用, 检测当前的接口是否为函数式接口
[Java] 纯文本查看 复制代码
// 格式
修饰符 interface 接口名称 {
	public abstract 返回值类型 方法名称(可选参数信息);
	// 其他非抽象方法内容
}

// 示例
@FunctionalInterface
public interface MyFunctionalInterface {
    void method();
}

函数式接口的使用
函数式接口的使用: 代替匿名内部类方式
函数式编程性能浪费的日志案例
日志: 就是存储程序运行信息的文本文件.
    我们平时打印输出一些信息是在控制台上, 如果将这些信息写入文本文件, 这些文件就是日志
[Java] 纯文本查看 复制代码
public static void showLog(int level, String message) {
        if (level == 1) {
            System.out.println(message);
        }
    }
    
	showLog(2, s1 + s2 + s3);
	// 先拼接s1+s2+s3出结果"helloworldjava", 然后才执行方法内部的判断
	// 相当于方法不需要执行, 但仍然在拼接字符串时浪费了一些性能

使用Lambda延迟执行的特性优化日志案例
Lambda具有延迟执行的特点:
        传递Lambda对象, 只有当符合执行条件时, 才会执行代码
[Java] 纯文本查看 复制代码
@FunctionalInterface
    interface MessageBuilder {
        String buildMessage();
    }

	public static void showLog(int level, MessageBuilder builder) {
        if (level == 1) {
            System.out.println(builder.buildMessage());
        }
    }
    
	showLog(2, () -> s1+s2+s3);
	// 传递Lambda对象, 即MessageBuilder实现类对象进方法
	// 判断2和1不相等, 所以不会执行builder.buildMessage()
	// 从而也不会执行重写方法中的s1+s2+s3
	// 避免了无意义的性能浪费

5分钟练习: 对比Lambda和普通方式执行效率
需求:
定义函数式接口 MessageBuilder, 使用@FunctionalInterface注解修饰
        定义抽象方法用于拼接字符串: String buildMessage();
定义测试类:
        定义方法模拟拼接大量字符串:
[Java] 纯文本查看 复制代码
public static String getString() {
            // 模拟拼接字符串的耗时
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String s1 = "hello";
            String s2 = "world";
            String s3 = "java";
            return s1 + s2 + s3;
        }

定义方法: public static void showLog(int level, String message)
                方法内部判断如果level==1, 则打印输出message
        定义方法: public static void showLogLambda(int level, MessageBuilder builder)
                方法内部判断如果level==1, 则打印输出builder.buildMessage()返回的字符串
        定义main方法:
                调用 showLog(2, getString()), 在方法调用前后获取毫秒值, 相减得出执行时间, 打印出来
                调用 showLogLambda(2, ()->getString());在方法调用前后获取毫秒值, 相减得出执行时间, 打印出来

代码:
[Java] 纯文本查看 复制代码
@FunctionalInterface
public interface MessageBuilder {
    String buildMessage();
}

public class Test {

    public static String getString() {
        // 模拟拼接字符串的耗时
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String s1 = "hello";
        String s2 = "world";
        String s3 = "java";
        return s1 + s2 + s3;
    }

    // 普通方式打印日志方法
    public static void showLog(int level, String message) {
        if (level == 1) {
            System.out.println(message);
        }
    }

    // Lambda方式打印日志方法
    public static void showLogLambda(int level, MessageBuilder builder) {
        if (level == 1) {
            System.out.println(builder.buildMessage());
        }
    }

    public static void main(String[] args) {
        // 统计普通方式消耗时间
        long start1 = System.currentTimeMillis();
        showLog(2, getString());
        long end1 = System.currentTimeMillis();
        System.out.println("普通方式耗时:" + (end1 - start1) + "毫秒");

        // 统计Lambda延迟执行方式耗时
        long start2 = System.currentTimeMillis();
        showLogLambda(2, ()->{return getString();});
        long end2 = System.currentTimeMillis();
        System.out.println("Lambda延迟执行方式耗时:" + (end2 - start2) + "毫秒");
    }
}

使用Lambda表达式作为方法参数
当一个方法的参数是一个函数式接口时, 可以使用Lambda表达式传递该参数, 简化匿名内部类的代码
5分钟练习: 函数式接口作为方法参数需求:
定义方法, 用来快速开启线程执行一个任务: public static void startThread(Runnable r)
        方法内部创建一个线程对象, 并将任务传递, 开启线程: new Thread(r).start();
在main方法中调用startThread()方法, 使用Lambda表达式方式, 传入一个任务, 任务中打印线程名+"线程启动了"
代码:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 匿名内部类方式
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "-->线程启动了");
            }
        });

        // Lambda表达式方式: 标准格式
        startThread(()->{
            System.out.println(Thread.currentThread().getName() + "-->线程启动了");
        });

        // Lambda表达式方式: 省略格式
        startThread(()->System.out.println(Thread.currentThread().getName() + "-->线程启动了"));
    }

    public static void startThread(Runnable r) {
        new Thread(r).start();
    }
}

使用Lambda表达式作为方法返回值
当一个方法的返回值是一个函数式接口时, 可以返回Lambda表达式, 简化匿名内部类的代码
5分钟练习: 使用Lambda表达式作为返回值需求:
定义方法, 用于获取一个比较器对象: public static Comparator<String> getComparator()
                                    return (String s1, String s2)->{...}}
    方法内部使用Lambda表达式作为Comparator接口的返回值, 比较规则是:
                第二个字符串参数的长度 - 第一个字符串参数的长度
在main方法中
        定义字符串数组: {"aaa", "b", "cccccc", "ddddddddddd"}
        调用 getComparator() 方法获取比较器对象
        调用 Arrays.sort(数组, 比较器) 方法, 将字符串数组排序, 然后打印出来
代码:
[Java] 纯文本查看 复制代码
public class Test {

    // 返回一个按照字符串长度降序的比较器对象
    private static Comparator<String> getComparator() {
        // 匿名内部类方式
        /*return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.length() - o1.length();
            }
        };*/

        // Lambda表达式: 标准格式
        /*return (String o1, String o2)->{
            return o2.length() - o1.length();
        };*/

        // Lambda表达式: 省略格式
        return (o1, o2)->o2.length() - o1.length();
    }

    public static void main(String[] args) {
        String[] arr = {"aaa", "b", "cccccc", "ddddddddddd"};

        System.out.println("排序前:" + Arrays.toString(arr));  // 排序前:[aaa, b, cccccc, ddddddddddd]
        Arrays.sort(arr, getComparator());
        System.out.println("排序后:" + Arrays.toString(arr));  // 排序后:[ddddddddddd, cccccc, aaa, b]
    }
}

常用函数式接口Supplier生产型函数式接口
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
        // 抽象方法
         T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 调用方法
        String s = getString( ()->"赵丽颖" );
        System.out.println(s);  // 赵丽颖
    }
    
    // 定义方法: 用来获取一个字符串 参数: 获取字符串的方式(代码)
    public static String getString(Supplier<String> sup) {
        return sup.get();
    }
}

Supplier生产型函数式接口练习: 求数组最大值5分钟练习: 使用Supplier接口求数组最大值
需求:
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值
定义测试类:
        定义方法, 用于获取数组中的最大值: public static int getMax(Supplier<Integer> sup)
                方法内部直接调用sup对象的 get() 方法获取得到的结果, 并return
        定义main方法:
                方法中定义数组: {100, 0, -50, 88, 99, 33, -30}
                调用 getMax() 方法, 方法内部传递Supplier接口的Lambda表达式
                表达式中编写获取数组最大值的代码
代码:
[Java] 纯文本查看 复制代码
public class Test {

    // 定义方法, 用于获取数组中的最大值, 传递的参数是: 获取数组最大值的实现代码
    private static int getMax(Supplier<Integer> supplier) {
        return supplier.get();
    }

    public static void main(String[] args) {
        // 定义数组
        int[] arr = {100, 0, -50, 88, 99, 33, -30};

        // 调用方法, 传递获取数组最大值的实现代码
        int result = getMax(()->{
            int max = arr[0];
            for (int i : arr) {
                if (i > max) {
                    max = i;
                }
            }
            return max;
        });
        System.out.println(result);  // 100

        // 使用函数式接口传递Lambda表达式的好处是: 可以省去定义方法, 直接将方法实现的代码传递执行
        // 比如下面就传递了另一种获取最大值的代码
        result = getMax(()->{
            int max = arr[0];
            for (int i = 1; i < arr.length; i++) {
                if (arr[i] > max) {
                    max = arr[i];
                }
            }
            return max;
        });
        System.out.println(result);  // 100
    }
}

Consumer消费型函数式接口
java.lang.StringBuilder类: 可变字符序列, 类似于String, 线程不安全效率高   "abc" -> "cba"
        StringBuilder reverse(): 将StringBuilder内部保存的内容反转
        String toString(): 转换为String   new StringBuilder("abc").reverse().toString()  "cba"
java.lang.StringBuffer类: 可变字符序列, 类似于String, 线程安全效率低
        StringBuffer reverse(): 将StringBuffer内部保存的内容反转
        String toString(): 转换为String

java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 抽象方法
        void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
[Java] 纯文本查看 复制代码
public class Test {

	// 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式
    public static void method(String name, Consumer<String> son1){
        son.accept(name);
    }

    public static void main(String[] args) {
        String name = "赵丽颖";

		// 消费这个字符串, 我们的消费方式是 反转字符串
        method(name, (String name)->{
        	// 反转字符串
            String reName = new StringBuilder(name).reverse().toString();
            System.out.println(reName);  // 颖丽赵

        });
    }
}

Consumer消费型函数式接口: 默认方法andThen()
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
[Java] 纯文本查看 复制代码
public class Test {

	// 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式1 和 消费方式2
    public static void method(String s, Consumer<String> con1, Consumer<String> con2){
//        con1.accept(s);
//        con2.accept(s);
        
		// 使用andThen简化
        one.andThen(two).accept(s);
    }

    public static void main(String[] args) {
		// 传入两种消费方式
        method("Hello",
               (t) -> {
                   System.out.println(t.toUpperCase()); // HELLO
               },
               (t) -> {
                   System.out.println(t.toLowerCase()); // hello
               });
    }
}

Consumer消费型接口练习: 字符串拼接输出5分钟练习: Consumer接口实现字符串拼接输出
需求:
下面的字符串数组当中存有多条信息, 请按照格式"姓名:XX. 性别:XX."格式将信息打印出来.
要求:
        将打印姓名的动作, 作为第一个Consumer接口的Lambda实例
        将打印性别的动作, 作为第二个Consumer接口的Lambda实例
        将两个Consumer接口按照顺序"拼接"到一起

public static void main(String[] args) {
          String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男" };
}

// 最终效果
姓名:迪丽热巴. 性别:女.
姓名:古力娜扎. 性别:女.
姓名:马尔扎哈. 性别:男.

被消费的字符串s: "迪丽热巴,女"
[Java] 纯文本查看 复制代码
// 消费方式1
String[] split = s.split(",");
String name = split[0];
System.out.print("姓名:"+name)

// 消费方式2
String[] split = s.split(",");
String gender = split[1];
System.out.println(". 性别:"+gender+".")

最终结果: 打印: 姓名:迪丽热巴. 性别:女.
代码:
[Java] 纯文本查看 复制代码
public class Test {

    // 定义方法, 用来将数组里面的元素打印为指定格式
    // 参数为: 数组, 消费方式1, 消费方式2
    private static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
        // 遍历出数组中的字符串元素, 最终消费的是字符串元素
        for (String message : arr) {
            // 连接两种消费方式, 然后消费字符串元素
            con1.andThen(con2).accept(message);
        }
    }

    public static void main(String[] args) {
        String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男" };

        // 调用方法消费
        printInfo(
                array,
                (message)->{  // 消费方式1: 打印姓名不换行
                    String name = message.split(",")[0];
                    System.out.print("姓名:" + name);
                },
                (message)->{  // 消费方式2: 打印性别换行
                    String gender = message.split(",")[1];
                    System.out.println(". 性别:" + gender + ".");
                }
        );
    }
}

Predicate条件判断函数式接口
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
        // 抽象方法
        boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现
        // 默认方法 (用于连接多个判断条件)
        default Predicate<T> and(Predicate<? super T> other): 与 &&
        default Predicate<T> or(Predicate<? super T> other): 或  ||
        default Predicate<T> negate(): 非, 取相反结果   !
[Java] 纯文本查看 复制代码
public class Test {
    
    // 定义方法用来检测字符串. 参数是 被检测的字符串 和 检测方式
    private static boolean checkString(String s, Predicate<String> pre) {
        return pre.test(s);
    }
    
    public static void main(String[] args) {
        String s = "abcde";
        
        boolean b = checkString(s, str -> str.length()>5);
        System.out.println(b);  // false
    }
}

Predicate条件判断函数式接口: 默认方法and()
[Java] 纯文本查看 复制代码
public class Test {
    // 定义方法用于按照2个条件检测字符串. 参数: 被检测的字符串, 检测条件1, 检测条件2
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
        //return pre1.test(s) && pre2.test(s);
        return pre1.and(pre2).test(s);
        // 两个条件必须同时满足
    }

    public static void main(String[] args) {
        String s = "abcdef";

        boolean b = checkString(
            s,
        	(String str)->{
            	return str.length()>5;    //判断字符串的长度是否大于5
        	},
        	(String str)->{
            	return str.contains("a"); //判断字符串中是否包含a
        	});
        System.out.println(b);
    }
}

Predicate条件判断函数式接口: 默认方法or(), negate()default Predicate<T> or(Predicate<? super T> other): 或
default Predicate<T> negate(): 非, 取相反结果
[Java] 纯文本查看 复制代码
// 或
public class Test {
    
    // 定义方法用于检测字符串. 参数 被检测的字符串, 检测方式1, 检测方式2
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
        //return pre1.test(s) || pre2.test(s);
        return  pre1.or(pre2).test(s);
        // 两个条件满足其一即可
    }

    public static void main(String[] args) {
        String s = "bc";
        
        boolean b = checkString(
            s,
            (String str)->{
            	return str.length()>5;     //判断字符串的长度是否大于5
        	},
            (String str)->{
            	return str.contains("a");  //判断字符串中是否包含a
        	});
        System.out.println(b);  // false
    }
}

// 取反
public class Test {
    
    // 定义方法用于检测字符串. 参数: 被检测字符串, 检测方式
    public static boolean checkString(String s, Predicate<String> pre){
        //return !pre.test(s);
        return  pre.negate().test(s);
        // 返回相反的结果
    }

    public static void main(String[] args) {
        String s = "abc";

        boolean b = checkString(
            s,
            (String str)->{
            	return str.length()>5;  //判断字符串的长度是否大于5,并返回结果
        	});
        System.out.println(b);  // true
    }
}

为什么需要将逻辑操作封装为方法?
  • 所有的默认方法返回值都是Predicate<T>, 也就是说可以实现链式调用
  • 如果没有这些方法, 直接用运算符可能无法完成目的

[Java] 纯文本查看 复制代码
return rule1.and(rule2)   // rule1 && rule2
	.or(rule3)            // || rule3
	.negate().or(rule4);  // || !rule4


Predicate条件判断函数式接口练习: 集合信息筛选5分钟练习: 使用Predicate实现集合信息筛选
需求:
数组当中有多条"姓名+性别"的信息如下, 请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中, 需要同时满足两个条件:
        1. 必须为女生
        2. 姓名为4个字
[Java] 纯文本查看 复制代码
public class DemoPredicate {
    public static void main(String[] args) {
      	String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
    }
}

代码:
[Java] 纯文本查看 复制代码
public class Test {

    // 定义方法, 将字符串数组中满足条件的元素过滤到ArrayList集合当中
    private static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
        // 创建一个空数组, 用于保存过滤到的元素
        ArrayList<String> list = new ArrayList<>();
        // 遍历数组
        for (String s : arr) {
            // 对每个元素进行条件判断
            boolean b = pre1.and(pre2).test(s);
            // 符合要求的添加到集合
            if (b) {
                list.add(s);
            }
        }
        // 返回集合
        return list;
    }


    public static void main(String[] args) {
        String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };

        ArrayList<String> list = filter(
                array,
                (String s)->{ // 判断条件1: 必须为女生
                    return s.split(",")[1].equals("女");
                },
                (String s)->{ // 判断条件2: 姓名为4个字
                    return s.split(",")[0].length() == 4;
                }
        );

        // 打印结果
        for (String s : list) {
            System.out.println(s);
        }
        /*
        迪丽热巴,女
        古力娜扎,女
         */
    }
}

Function转换型函数式接口
函数 y = f(x)
java.util.function.Function<T,R>: 根据一个 T类型的数据 转换为 另一个R类型的数据
        T称为前置条件, 也就是输入(input)的类型
        R称为后置条件, 也就是返回结果(result)的类型
        有进有出, 所以称为"函数Function"
        // 抽象方法
        R apply(T t): 将T转换为R
        // 默认方法
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
[Java] 纯文本查看 复制代码
public class Test {

    // 定义方法用于将String转换为Integer. 参数: 被转换的字符串, 将String转换为Integer的方式
    public static void change(String s, Function<String,Integer> fun){
        //Integer in = fun.apply(s);
        int in = fun.apply(s);
        System.out.println(in);
    }

    public static void main(String[] args) {
        String s = "1234";

        change(
            s,
            (String str)->{
            	return Integer.parseInt(str);  //把字符串类型的整数,转换为Integer类型的整数返回
        	});
        
        //优化Lambda
        change(s, str->Integer.parseInt(str));
    }
}

Function转换型函数式接口: 默认方法andThen()
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 连接多种转换操作, 先做什么, 再做什么
[Java] 纯文本查看 复制代码
public class Test {
    
    // 定义方法用于将String转换为Integer, 然后再将Integer转换为String
    // 参数: 被转换的字符串, String转Integer的方式, Integer转String的方式 
    public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2){
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }

    public static void main(String[] args) {
        String s = "123";

        change(
            s,
            (String str)->{
            	return Integer.parseInt(str)+10;   //把字符串转换为整数+10
        	},
            (Integer i)->{
            	return i+"";   //把整数转换为字符串
        	});

        //优化Lambda表达式
        change(
            s, 
            str->Integer.parseInt(str)+10, 
            i->i+""
        );
    }
}

Function转换型函数式接口: 使用Function连续转换5分钟练习: 使用Function连续转换需求:
请使用Function进行函数模型的拼接, 按照顺序需要执行的多个函数操作为:
        String str = "赵丽颖,20";
1. 将字符串截取数字年龄部分, 得到字符串 String->String
2. 将上一步的字符串转换成为int类型的数字 String->Integer
3. 将上一步的int数字累加100, 得到结果int数字 Integer->Integer
代码:
[Java] 纯文本查看 复制代码
public class Test {

    // 定义方法, 将字符串转换为要求的int值
    private static int change(String s, Function<String, String> fun1,
                              Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
        // 连续转换, 并返回结果
        return fun1.andThen(fun2).andThen(fun3).apply(s);
    }

    public static void main(String[] args) {
        String str = "赵丽颖,20";

        /*int result = change(
                str,
                (String s)->{  // 将字符串截取数字年龄部分
                    return s.split(",")[1];
                },
                (String s)->{  // 将上一步的字符串转换成为int类型的数字
                    return Integer.parseInt(s);
                },
                (Integer i)->{ // 将上一步的int数字累加100, 得到结果int数字
                    return i+100;
                }
        );*/

        // 省略格式
        int result = change(
                str,
                s->s.split(",")[1],  // 将字符串截取数字年龄部分
                s->Integer.parseInt(s),     // 将上一步的字符串转换成为int类型的数字
                i->i+100                    // 将上一步的int数字累加100, 得到结果int数字
        );

        System.out.println(result);  // 120
    }
}

今日API
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
        // 抽象方法
         T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现
         
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 抽象方法
        void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
       
java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断
        // 抽象方法
        boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现
        // 默认方法 (用于连接多个判断条件)
        default Predicate<T> and(Predicate<? super T> other): 与
        default Predicate<T> or(Predicate<? super T> other): 或
        default Predicate<T> negate(): 非, 取相反结果
       
java.util.function.Function<T,R>: 根据一个T类型的数据得到另一个R类型的数据
        T称为前置条件, 也就是输入(input)的类型
        R称为后置条件, 也就是返回结果(result)的类型
        有进有出, 所以称为"函数Function"
        // 抽象方法
        R apply(T t): 将T转换为R
        // 默认方法
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换

























4 个回复

倒序浏览
沙发顺便点赞!
回复 使用道具 举报
回复 使用道具 举报
656666666666666666666666
回复 使用道具 举报
6666666666666666666666
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马