• Java 函数式接口、lambda表达式、初识Stream


    1.函数式接口:

    有且仅有一个函数接口(可以有其他非抽象的方法),函数式接口的典型使用场景就是作为方法的入参。
    比如 java.lang.Runnable就是一个函数式接口。java.util.function包中提供了丰富的函数式接口:Supplier、Consummer、Function等。

    2.@FunctionalInterface

    用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则会将会报错。与@Override注解类似。

    示例:

    @FunctionalInterface
    public interface MyFunctionalInterface {
        void myMethod();
    }
    
    public class DemoMyFunctionalInterface {
        // 自定义的函数式接口作为方法的参数
        private static void doSomething(MyFunctionalInterface inter) {
            inter.myMethod(); // 调用自定义的函数式接口方法
        }
    
        public static void main(String[] args) {
    
            // 通过匿名内部类操作 使用了调用函数式接口的方法
            doSomething(new MyFunctionalInterface() {
                @Override
                public void myMethod() {
                    System.out.println("匿名内部类 执行");
                }
            });
    
            // 通过lambda操作 使用了调用函数式接口的方法
            doSomething(() -> System.out.println("lambda 执行"));
        }
    }
    

    3. lambda

    3.1 Lambda表达式, 也可以称为闭包,它是推动 java 8 发布的最重要的新特性。Lambda允许把函数作为一个方法的参数(即就是,函数作为参数传递进方法中)。Lambda表达式的一个重要的用法就是简化某些匿名内部类的写法。
    Lambda标准格式:(参数类型 参数名)->{代码块儿/代码语句}
    3.2 省略规则:
    Lambda标准格式的基础上,使用省略写法的规则:
    (1)小括号内参数的类型可以可以省略;
    (2)如果小括号内有且仅有一个参数,则小括号可以省略;
    (3)如果打括号内有且仅有一个语句,则无论是否返回值,都可以省略大括号、return 关键字以及语句分号。

    示例:

    @FunctionalInterface
    public interface MessageBuilder {
        String buildMessage();
    }
    
    public class DemoMessageBuilderLogger {
    
        private static void traditionalLog(int level, String msg) {
            if (level == 1) {
                System.out.println(msg);
            }
        }
    
        private static void lambdaLog(int level, MessageBuilder builder){
            if (level == 1){
                System.out.println(builder.buildMessage());
            }
        }
    
        public static void main(String[] args) {
            String msgA = "Hello";
            String msgB = "World";
            String msgC = "Java";
    
            traditionalLog(1, msgA + msgB + msgC);
    
            lambdaLog(1, new MessageBuilder() {
                @Override
                public String buildMessage() {
                    return msgA + msgB + msgC;
                }
            });
    
            lambdaLog(1,() -> msgA + msgB + msgC);
        }
    

    注意:
    使用Lambda的依据必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口),Lambda的实际类型就是对应函数类型的接口类型。

    具体内部怎么调用与实现的呢?
    JVM内部就是通过invokedynamic指令来实现Lambda表达式的的hi用Lambda简化过的匿名内部类在外部类编译后不会生成内部类的class文件,Lambda表达式被封装成了主类的一个私有方法。并通过invokedynamic 指令进行调用。
    lambda是延迟执行的,有些场景的代码执行后,执行结果不一定会被使用,从而造成性能的浪费。而lambda 表达式是延迟执行的,正好可以作为解决方案,提升性能。

    4.初识 Stream

    这里的Stream到底是什么呢?
    说到Stream我们很容易想到I/O Stream,然而实际上没有人规定“流”就一定是“io流”,所以在java 8中得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库存在的弊端。

    我们知道集合中要进行频繁的遍历操作,然而我们经常使用的都是循环遍历,每次需要遍历的操作都需要从 for从前到后遍历集合,比较麻烦。

    我们可以大胆进行对比各种遍历的代码量:

      List<String> list = new ArrayList<>();
            list.add("张无忌");
            list.add("周芷若");
            list.add("赵敏");
            list.add("张强");
            list.add("张三丰");
    
            /**
             * 普通的遍历
             */
            System.out.println("普通遍历:");
            for (int i = 0; i < list.size(); i++){
                System.out.println(list.get(i));
            }
            System.out.println("---------------------");
            /**
             * 增强for循环
             */
            System.out.println("增强for遍历:");
            for (String s : list){
                System.out.println(s);
            }
            System.out.println("******************");
            /**
             * 使用迭代器Iterator进行遍历
             */
            System.out.println("利用Iterator遍历:");
            Iterator<String> iterator = list.iterator();
            while(iterator.hasNext()){
                String s = iterator.next();
                System.out.println(s);
            }
    
            /**
             * 使用Stream 进行遍历
             */
            System.out.println("使用Stream遍历:");
            list.stream().forEach(System.out::println);
    
    
    

    输出结果:

    普通遍历:
    张无忌
    周芷若
    赵敏
    张强
    张三丰


    增强for遍历:
    张无忌
    周芷若
    赵敏
    张强
    张三丰


    利用Iterator遍历:
    张无忌
    周芷若
    赵敏
    张强
    张三丰


    使用Stream遍历:
    张无忌
    周芷若
    赵敏
    张强
    张三丰

    到这我们差不多认识了这家伙,后期继续会深入的进行了解并在开发中进行大量的使用。

  • 相关阅读:
    Femas:云原生多运行时微服务框架
    C语言回调函数
    【华为OD机试真题 JAVA】叠积木
    【论文阅读】2736. 最大和查询-2023.11.17
    对象的关联
    腾讯云[HiFlow】| 自动化 -------HiFlow:还在复制粘贴?
    页面加载动画_渐隐变色旋转小圆圈
    恩智浦i.MX8MM核心板在智能售货机产品中的应用方案-迅为电子
    Ubuntu 18.04 中 卸载/安装G2O库
    sqlmap基本使用方法
  • 原文地址:https://blog.csdn.net/m0_52318340/article/details/127121255