• 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遍历:
    张无忌
    周芷若
    赵敏
    张强
    张三丰

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

  • 相关阅读:
    当知识管理遇上企业云盘一体机
    泰凌微BLE(2):ATT自定义UUID并实现Notification数据传输
    虚拟列表(附带动态加载)原理及实现
    OpenCV C++ 张正友相机标定【相机标定原理、相机标定流程、图像畸变矫正】
    第十九章 cookie和session
    HDLbits exercises 4 (MORE VERILOG FEATURES节选题)
    软件临界资源访问冲突
    搭建本地MQTT服务器
    使用词袋模型(BoW)测试提取图像的特征点和聚类中心
    SSRF 漏洞笔记
  • 原文地址:https://blog.csdn.net/m0_52318340/article/details/127121255