• 函数式编程-Stream流(三更草堂)


    1. 概述

    1.1 为什么学?

    • 能够看懂公司里的代码
    • 大数量下处理集合效率高 (并行流)(多线程,并发编程)
    • 代码可读性高
    • 消灭嵌套地狱
    //查询未成年作家的评分在70以上的书籍 由于洋流影响所以作家和书籍可能出现重复,需要进行去重
    List<Book> bookList = new ArrayList<>();
    Set<Book> uniqueBookValues = new HashSet<>();
    Set<Author> uniqueAuthorValues = new HashSet<>();
    for (Author author : authors) {
        if (uniqueAuthorValues.add(author)) {
            if (author.getAge() < 18) {
                List<Book> books = author.getBooks();
                for (Book book : books) {
                    if (book.getScore() > 70) {
                        if (uniqueBookValues.add(book)) {
                            bookList.add(book);
                        }
                    }
                }
            }
        }
    }
    System.out.println(bookList);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    =====> 函数式编程:

    List<Book> collect = authors.stream()
        .distinct()
        .filter(author -> author.getAge() < 18)
        .map(author -> author.getBooks())
        .flatMap(Collection::stream)
        .filter(book -> book.getScore() > 70)
        .distinct()
        .collect(Collectors.toList());
    System.out.println(collect);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.2 函数式编程思想

    1.2.1 概念

    面向对象思想需要关注用什么对象完成什么事情。而函数式编程思想就类似于我们数学中的函数。它主要关注的是对数据进行了什么操作。

    函数式编程(Functional Programming,简称FP)是一种编程范式,它强调将计算视为数学函数的求值过程,并避免在程序中使用可变状态和可变数据。函数式编程的核心思想是将计算过程分解为一系列纯函数的调用,其中每个函数都接受输入并生成输出,而且在给定相同输入时总是产生相同的输出,不会产生副作用。

    以下是函数式编程的一些重要概念和原则:

    1. 纯函数(Pure Functions):纯函数是指在给定相同的输入时,总是返回相同的输出,并且不会改变外部状态或产生副作用。这意味着纯函数不依赖于外部变量,不修改全局状态,也不进行 I/O 操作。

    2. 可变性(Immutability):函数式编程鼓励使用不可变数据结构,即一旦创建就不能修改的数据。这有助于避免竞态条件和意外的副作用。

    3. 高阶函数(Higher-order Functions):函数可以作为参数传递给其他函数,或者从其他函数中返回。这使得函数可以更灵活地组合和重用。

    4. 声明式编程(Declarative Programming):函数式编程通常更注重"做什么"而不是"如何做"。开发者描述期望的结果,而不是详细指定如何实现这些结果。

    5. 不可变性(Immutability):函数式编程鼓励使用不可变数据结构,即一旦创建就不能修改的数据。这有助于避免竞态条件和意外的副作用。

    6. 惰性评估(Lazy Evaluation):在函数式编程中,表达式通常在需要时才会被求值,而不是立即求值。这可以提高性能和节省资源。

    7. 递归(Recursion):函数式编程通常使用递归来处理重复的任务,而不是循环。递归更符合函数式编程的思想,并且可以帮助实现简洁的代码。

    8. 不可变性(Immutability):函数式编程鼓励使用不可变数据结构,即一旦创建就不能修改的数据。这有助于避免竞态条件和意外的副作用。

    函数式编程通常被认为是一种强大的编程范式,可以帮助开发者编写更具表现力、可维护性和并发性的代码。它在现代编程语言和框架中得到广泛支持,如Haskell、Clojure、Scala、JavaScript的某些库等。虽然函数式编程可能需要开发者重新思考编程的方式,但它可以带来很多优点,特别是在处理复杂问题和并发编程时。

    1.2.2 优点

    • 代码简洁,开发快速
    • 接近自然语言,易于理解
    • 易于"并发编程

    2. Lambda表达式 —>可以考虑先构造匿名内部类

    2.1 概述

    Lambda是JDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作

    2.2 核心原则

    可推导可省略
    即,可以被推导出来的属性,那么也就可以去省略它。

    2. 3 基本格式

    (参数列表)->{代码}
    
    • 1
    例一,

    我们在创建线程并启动时可以使用匿名内部类的写法:

    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("你知道吗 我比你想象的 更想在你身边");
        }
    }).start();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以使用Lambda的格式对其进行修改。修改后如下:

    new Thread(()->{
        System.out.println("你知道吗 我比你想象的 更想在你身边");
    }).start();		//调start方法,启动线程。
    
    • 1
    • 2
    • 3
    例二:

    现有方法定义如下,其中IntBinaryOperator是一个接口。先使用匿名内部类的写法调用该方法。

    public static int calculateNum(IntBinaryOperator operator){
            int a = 10;
            int b = 20;
            return operator.applyAsInt(a, b);
        }public static void main(String[] args) {
            int i = calculateNum(new IntBinaryOperator() {		//并行写法???
                @Override
                public int applyAsInt(int left, int right) {
                    return left + right;
                }
            });
            System.out.println(i);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Lambda写法: IDEA内按alt+enter ,可以转lambda表达式形式。

        public static void main(String[] args) {
            int i = calculateNum((int left, int right)->{
                return left + right;
            });
            System.out.println(i);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    例三

    现有方法定义如下,其中IntPredicate是一个接口。先使用匿名内部类的写法调用该方法。

        public static void printNum(IntPredicate predicate){
            int[] arr = {1,2,3,4,5,6,7,8,9,10};
            for (int i : arr) {
                if(predicate.test(i)){		//属性调方法,可能是它自己的,
                //										也可能是来自它的类,定义的方法。
                    System.out.println(i);
                }
            }
        }
        //---------------------------------------------------------------
        public static void main(String[] args) {
            printNum(new IntPredicate() {
                @Override
                public boolean test(int value) {
                    return value%2==0;
                }
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    例四(泛型lambda化)

    现有方法定义如下,其中Function是一个接口。先使用匿名内部类的写法调用该方法。

        public static <R> R typeConver(Function<String,R> function){
            String str = "1235";
            R result = function.apply(str);
            return result;
        }
        public static void main(String[] args) {
            Integer result = typeConver(new Function<String, Integer>() {
                @Override
                public Integer apply(String s) {
                    return Integer.valueOf(s);
                }
            });
            System.out.println(result);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Lambda写法:

            Integer result = typeConver((String s)->{
                return Integer.valueOf(s);
            });
            System.out.println(result);
    
    • 1
    • 2
    • 3
    • 4
    例五

    现有方法定义如下,其中IntConsumer是一个接口。先使用匿名内部类的写法调用该方法。

        public static void foreachArr(IntConsumer consumer){
            int[] arr = {1,2,3,4,5,6,7,8,9,10};
            for (int i : arr) {
                consumer.accept(i);
            }
        }
        public static void main(String[] args) {
            foreachArr(new IntConsumer() {
                @Override
                public void accept(int value) {
                    System.out.println(value);
                }
            });
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Lambda写法:

        public static void main(String[] args) {
            foreachArr((int value)->{
                System.out.println(value);
            });
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4 省略规则

    • 参数类型可以省略
    • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
    • 方法只有一个参数时小括号可以省略
    • 以上这些规则都记不住也可以省略不记

    尚硅谷—lambda表达式

    1.Lambda表达式使用前后的对比:

    1.Lambda表达式使用前后的对比:
    举例一:
    @Test
    public void test1(){
    
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱北京天安门");
            }
        };
    
        r1.run();
    
        System.out.println("***********************");
    
        Runnable r2 = () -> System.out.println("我爱北京故宫");
    
        r2.run();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    举例二:
    @Test
    public void test2(){
    
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
    
        int compare1 = com1.compare(12,21);
        System.out.println(compare1);
    
        System.out.println("***********************");
        //Lambda表达式的写法
        Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1,o2);
    
        int compare2 = com2.compare(32,21);
        System.out.println(compare2);
    
    
        System.out.println("***********************");
        //方法引用
        Comparator<Integer> com3 = Integer :: compare;
    
        int compare3 = com3.compare(32,21);
        System.out.println(compare3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2.lambda表达式的基本用法:

    在这里插入图片描述

    3.如何使用:

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    人生阶段总结
    将java的项目jar包打成镜像
    ES6类和继承
    回顾多线程
    iOS 17隐私设置指南
    前端面试宝典React篇09 Virtual DOM 的工作原理是什么?
    c语言(看一遍就会操作,小马教一步步教你如何文件操作)
    外包干了2个月,技术退步明显。。。。。
    【微信小程序】常用组件基本使用(viewscroll-viewswiper、textrich-text、buttonimage)
    KafKa3.x基础
  • 原文地址:https://blog.csdn.net/weixin_43554580/article/details/133384107