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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小石姐姐 于 2018-12-6 17:06 编辑

day12 函数式接口 今日内容
自定义函数式接口
        @FunctionalInterface 注解
Lambda表达式:
        Lambda表达式的"延迟执行"的特点
        函数式接口作为方法的"参数"和"返回值类型"
常用函数式接口
        Supplier: 生产型函数式接口         获取值
        Consumer: 消费型函数式接口         使用值
        Predicate: 条件判断型函数式接口    判断值
        Function: 转换型函数式接口         转换值
``` 函数式接口
函数式接口概念, 自定义函数式接口知识点:
什么是函数式接口
如何自己定义一个函数式接口
@FunctionalInterface 注解有什么作用
```总结:
函数式接口: JDK 8 新特性
    有且仅有一个抽象方法的接口, 适用于函数式编程场景的接口
    (默认方法, 静态方法, 私有方法, 与 java.lang.Object 类中定义相同的抽象方法, 都不算作抽象方法)
自定义函数式接口:
        接口中有且只有一个抽象方法@FunctionalInterface的作用:
        在接口上使用, 检测当前的接口是否为函数式接口
```补充:
// 格式
修饰符 interface 接口名称 {
        public abstract 返回值类型 方法名称(可选参数信息);
        // 其他非抽象方法内容
}// 示例
[Java] 纯文本查看 复制代码
@FunctionalInterface
public interface MyFunctionalInterface {
    void method();
}

``` 函数式接口的使用知识点:```
定义了函数式接口后, 如何使用它
```总结:
函数式接口的使用:
        作为方法的参数类型, 传递Lambda表达式, 代替匿名内部类方式
```补充:
public static void method(Animal a) {  // 传递实现类对象  Animal a = new Cat();
    a.eat();
}public static void method(Runnable r) {  // 传递实现类对象  Runnable r = new Runnable(){}
    new Thead(r).start();
}
``` 函数式编程
性能浪费的日志案例知识点:```
演示代码的方法中, 传递的字符串参数是否需要先拼接, 才能传入方法内部
```总结:
日志: 就是存储程序运行信息的文本文件.
    我们平时打印输出一些信息是在控制台上, 如果将这些信息写入文本文件, 这些文件就是日志
   
      
   
      
[AppleScript] 纯文本查看 复制代码
  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具有"延迟执行"的特点:
        传递Lambda对象, 只有当符合执行条件时, 才会执行代码
      
[Java] 纯文本查看 复制代码
     @FunctionalInterface
    interface MessageBuilder {
        String buildMessage();
    }        public static void showLog(int level, MessageBuilder builder) { // 传递实现类对象
        if (level == 1) {
                String s = builder.buildMessage();
            System.out.println(s);
        }
    }
   
    showLog(1, new MessageBuilder(){
                @Override
        public String buildMessage() {
            return s1 + s2 + s3;
        }
    });
   
        showLog(2, () -> s1+s2+s3);
        // 传递Lambda对象, 即MessageBuilder实现类对象进方法
        // 判断2和1不相等, 所以不会执行builder.buildMessage()
        // 从而也不会执行重写方法中的s1+s2+s3
        // 避免了无意义的性能浪费
  
   
```补充:``` 5分钟练习: 对比Lambda和普通方式执行效率
需求:
定义函数式接口 MessageBuilder, 使用@FunctionalInterface注解修饰
        定义抽象方法用于拼接字符串: String buildMessage();
定义测试类:
        定义方法模拟拼接大量字符串:

[AppleScript] 纯文本查看 复制代码
 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());在方法调用前后获取毫秒值, 相减得出执行时间, 打印出来
```代码:
[AppleScript] 纯文本查看 复制代码
public interface MessageBuilder {
    // 用于拼接字符串的方法, 怎么拼, 需要我们传递Lambda来实现
    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) {
            String s = builder.buildMessage();
            System.out.println(s);
        }
    }
   
    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, ()->getString());
        long end2 = System.currentTimeMillis();
        System.out.println("延迟执行方式耗时:" + (end2-start2));
    }
}
```

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

      
[AppleScript] 纯文本查看 复制代码
  // Lambda标准格式传递参数
        startThread(()->{
            System.out.println(Thread.currentThread().getName() + "线程启动了");
        });        // Lambda省略格式传递参数
        startThread(()->System.out.println(Thread.currentThread().getName() + "线程启动了"));
    }    // 练习调用参数是函数式接口的方法, 可以向参数传递Lambda表达式
    public static void startThread(Runnable r) {
        new Thread(r).start();
    }
}`

      `` 使用Lambda表达式作为方法返回值知识点:
接口: 可以作为方法的参数类型, 还可以作为方法的返回值类型
当一个方法的返回值是一个函数式接口时, Lambda表达式方式是否比匿名内部类方式简单
[AppleScript] 纯文本查看 复制代码
public static Comparator<String> getComparator(){
    return new Comparator<String>(){
                @Override
        public int compare(String o1, String o2) {
                // 编写比较的规则 升序
                return o1.length()-o2.length();
        }
    };
}

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

``` 常用函数式接口
Java中提供的常用 函数式接口:
        Supplier<T>: 生产型函数式接口         获取值  a和b的和, 获取数组最大值, 获取一个Person对象
        Consumer<T>: 消费型函数式接口         使用值  给它一个String让他打印, 给它一个对象
        Predicate<T>: 条件判断型函数式接口     判断值  判断字符串长度是否大于5
        Function<T, R>: 转换型函数式接口      转换值  给它一个String转换为Integer "123"->123
``` Supplier生产型函数式接口知识点:
JDK 提供的函数式接口在哪个包中
Supplier<T> 接口有什么作用
```总结:
java.util.function.Supplier<T>函数式接口: 生产型函数式接口
        // 抽象方法
         T get(): 用于获取一个对象或值.
            至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现
```补充:

   
   
[AppleScript] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 调用方法
        String s = getString( ()->"赵丽颖" );
        System.out.println(s);  // 赵丽颖
        
        // 相当于
        getString(new Supplier<String>(){
            @Override
            public String get() {
                return "赵丽颖";
            }
        });
    }
 // 定义方法: 用来获取一个字符串 参数: 获取字符串的方式(代码)
    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 {    // 方法的作用: 获取最大值  至于怎么获取, 获取什么的最大值, 需要我们传递Lambda表达式来实现
    // 参数的作用: 获取最大值的方式(代码)
    public static int getMax(Supplier<Integer> sup) {
        return sup.get();
    }    public static void main(String[] args) {
        int[] arr =  {100, 0, -50, 88, 99, 33, -30};        // 调用方法来获取数组中的最大值, 怎么获取呢? 我们来传递Lambda表达式实现        // 一开始不熟悉抽象方法的参数和返回值类型, 可以先写匿名内部类, 然后改写为Lambda
        /*int maxValue = getMax(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int max = 0;
                for (int i : arr) {
                    if (i > max) {
                        max = i;
                    }
                }
                return max;
            }
        });*/        // Lambda方式
        int maxValue = getMax(()->{
            int max = 0;
            for (int i : arr) {
                if (i > max) {
                    max = i;
                }
            }
            return max;
        });        System.out.println("最大值:" + maxValue);
    }
}

``` Consumer消费型函数式接口知识点:
Consumer<T> 接口有什么作用
```总结:
java.lang.StringBuilder类: 可变字符序列, 类似于String, 线程不安全效率高   
        StringBuilder reverse(): 将StringBuilder内部保存的内容反转
        String toString(): 转换为String
                new StringBuilder("abc").reverse().toString(); -> "cba" "abc" -> "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对象实现连续操作. 谁写前面, 谁先消费
```补充:
[AppleScript] 纯文本查看 复制代码
public class Test {        // 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式
    public static void method(String name, Consumer<String> con){
        con.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()知识点:
Consumer<T>接口中的默认方法 Consumer<T> andThen(Consumer<? super T> after) 如何简化多个Consumer的消费
```总结:
java.util.function.Consumer<T>函数式接口: 消费型函数式接口
        // 默认方法
        default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费
```补充:
public class Test {        // 定义方法用来消费一个字符串. 参数是 被消费的字符串 和 消费方式1 和 消费方式2
    public static void method(String s, Consumer<String> con1, Consumer<String> con2){
//        con1.accept(s);
//        con2.accept(s);
        
                // 使用andThen简化
        con1.andThen(con2).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接口实现字符串拼接输出
需求:
字符串数组String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};当中存有多条信息, 请按照格式"姓名:XX。性别:XX。"格式将信息打印出来.
要求:
        将打印姓名的动作, 作为第一个Consumer接口的Lambda实例
        将打印性别的动作, 作为第二个Consumer接口的Lambda实例
        将两个Consumer接口按照顺序"拼接"到一起public class Test {
   
[AppleScript] 纯文本查看 复制代码
 public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
                // 补全代码
    }
   
    public static void main(String[] args) {
        String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};
        
        // 调用printInfo方法
    }
}

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

分析:
被消费的字符串s: "迪丽热巴,女"
// 消费方式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+"。")
   
最终结果: 姓名:迪丽热巴。性别:女。
```代码:
[AppleScript] 纯文本查看 复制代码
public class Test {    // 方法的作用: 将一个字符串数组进行消费, 使用2种消费方式
    // 参数的作用: 被消费的字符串数组, 消费方式1, 消费方式2
    public static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2) {
        // 遍历字符串数组, 取出每个信息
        for (String message : arr) {
            // 对每个信息进行2次消费
            con1.andThen(con2).accept(message);  // 消费这个字符串, 至于怎么消费, 需要我们传递Lambda实现
        }
    }    public static void main(String[] args) {
        String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};        // 如果直接写Lambda不熟练, 可以先写匿名内部类
        printInfo(   // 可以将3个参数换行, 便于查看
                array,
                new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        // 消费方式1: 提取姓名并按格式打印
                        String name = s.split(",")[0];
                        System.out.print("姓名:" + name);
                    }
                },
                new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        // 消费方式2: 提取性别并按格式打印
                        String age = s.split(",")[1];
                        System.out.println("。性别:" + age + "。");
                    }
                });        // Lambda方式
        printInfo(
                array,
                message -> {
                    // 消费方式1: 提取姓名并按格式打印
                    String name = message.split(",")[0];
                    System.out.print("姓名:" + name);
                },
                message -> {
                    // 消费方式2: 提取性别并按格式打印
                    String age = message.split(",")[1];
                    System.out.println("。性别:" + age + "。");
                }
        );
    }
}

```
Predicate条件判断函数式接口知识点:
Predicate<T> 函数式接口有什么作用
```总结:
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(): 非, 取相反结果   !
   
   
    boolean b = 判断方式1.or(判断方式2).and(判断方式3).negate().test("abc")
```补充:
[AppleScript] 纯文本查看 复制代码
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()知识点:
Predicate接口中的默认方法 and() 如何实现多个条件"与"的判断
```总结:
default Predicate<T> and(Predicate<? super T> other): 与
```补充:
[AppleScript] 纯文本查看 复制代码
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()知识点:
Predicate接口中的默认方法 or() 如何实现多个条件"或"的判断
Predicate接口中的默认方法 negate() 如何实现多个条件"非"的判断
```总结:
default Predicate<T> or(Predicate<? super T> other): 或
default Predicate<T> negate(): 非, 取相反结果
```补充:
// 或
[AppleScript] 纯文本查看 复制代码
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条件判断函数式接口练习: 集合信息筛选
5分钟练习: 使用Predicate实现集合信息筛选
需求:
数组当中有多条"姓名+性别"的信息如下, 请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中, 需要同时满足两个条件:
        1. 必须为女生
        2. 姓名为4个字public class Test {        // 将字符串数组中满足条件的元素过滤到ArrayList集合当中
    private static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
        // 按照判断方式补全代码
    }    public static void main(String[] args) {
              String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
              
              // 补全代码, 调用filter()方法
    }
}
```代码:
[AppleScript] 纯文本查看 复制代码
public class Test {    // 方法的作用: 按照2个判断方式, 过滤一个String[], 并将满足条件的结果放入ArrayList返回
    public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
        // 创建一个新集合
        ArrayList<String> list = new ArrayList<>();
        // 遍历数组, 将满足条件的元素放入集合
        for (String s : arr) {
            if (pre1.and(pre2).test(s)) {  // 至于怎么判断, 需要我们传递Lambda来实现
                list.add(s);
            }
        }
        // 返回集合
        return list;
    }
    public static void main(String[] args) {
        String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };        // 调用方法, 匿名内部类方式
        ArrayList<String> result1 = filter(
                array,
                new Predicate<String>() {
                    @Override
                    public boolean test(String s) {
                        // 必须为女生
                        return s.split(",")[1].equals("女");
                    }
                },
                new Predicate<String>() {
                    @Override
                    public boolean test(String s) {
                        // 姓名为4个字
                        return s.split(",")[0].length() == 4;
                    }
                }
        );
        System.out.println(result1);        // 调用方法, Lambda方式
        ArrayList<String> result2 = filter(
                array,
                s -> s.split(",")[1].equals("女"),
                s -> s.split(",")[0].length() == 4
        );
        System.out.println(result2);
    }
}

``` Function转换型函数式接口知识点:
Function<T,R> 有什么作用"a"->
"a"->
   
   
"1"->1->10
```总结:
函数 y = f(x)
java.util.function.Function<T,R>: 根据一个 T类型的数据 转换为 另一个R类型的数据
        T是 输入(input)的类型
        R是 返回结果(result)的类型
        有进有出, 所以称为"函数Function"
        // 抽象方法
        R apply(T t): 将T转换为R. 至于T和R是什么类型, 以及如何转换, 需要传递Lambda表达式实现
        // 默认方法
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
```补充:
[AppleScript] 纯文本查看 复制代码
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);  //把"1234"转换为Integer类型的整数返回
                });
        
        //Lambda省略格式
        change(s, str->Integer.parseInt(str));
    }
}

``` Function转换型函数式接口: 默认方法andThen()知识点:
Function接口中的 andThen() 如何组合多种转换方法
```总结:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 连接多种转换操作, 先做什么, 再做什么
```补充:
[AppleScript] 纯文本查看 复制代码
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
最后将结果打印出来
[AppleScript] 纯文本查看 复制代码
public class Test {
    public static int change(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
                // 补全代码
    }
   
    public static void main(String[] args) {
            String str = "赵丽颖,20";
            // 调用change方法
    }
}

```代码:
[AppleScript] 纯文本查看 复制代码
public class Test {    // 方法作用: 按照步骤将字符串转换
    // 参数: 被转换的字符串, 转换方式1, 转换方式2, 转换方式3
    public 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 num1 = change(
                str,
                new Function<String, String>() {  // 将字符串截取数字年龄部分, 得到字符串
                    @Override
                    public String apply(String s) {
                        return s.split(",")[1];
                    }
                },
                new Function<String, Integer>() {  // 将上一步的字符串转换成为int类型的数字
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s);
                    }
                },
                new Function<Integer, Integer>() { // 将上一步的int数字累加100, 得到结果int数字
                    @Override
                    public Integer apply(Integer integer) {
                        return integer + 100;
                    }
                }
        );
        System.out.println(num1);        // Lambda方式
        int num2 = change(
                str,
                s -> s.split(",")[1],
                s -> Integer.parseInt(s),
                i -> i + 100
        );
        System.out.println(num2);
    }
}

```--- 今日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转换
``` 今日目标 能够使用@FunctionalInterface注解
@FunctionalInterface注解 检测是否是函数式接口
``` 能够理解Lambda延迟执行的特点
当需要去调用抽象方法时, 才执行传入的Lambda表达式
``` 能够使用Lambda作为方法的参数
方法参数是函数式接口类型时, 才能使用Lambda作为参数
```
能够使用Supplier<T>函数式接口
生产型
获取值T get()
``` 能够使用Consumer<T>函数式接口
消费型
使用值void accept(T t): 消费指定的参数.
Consumer andThen(Consumer c)
``` 能够使用Predicate<T>函数式接口
判断型
判断值boolean test(T t): 判断参数值, 返回判断结果Predicate and(Predicate p)
Predicate or(Predicate p)
Predicate negate()
``` 能够使用Function<T, R>函数式接口
转换型
转换值R apply(T t): 将T转换为RFunction andThen(Function f)
```

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马