• Java函数式编程


    Functional Programming 函数式编程,这里的函数类似于一个表达式,类似我们学习中的数学公式,输入端是确定的,那输出端也是确定的,这种就是没有副作用的纯函数。

    函数式编程认为,程序可以用一系列数学函数或表达式的组合来表示。函数式编程是程序面向数学的更底层的抽象,将计算过程描述为表达式。抽象程度很高,但是也只是理论上,毕竟不是所有的程序都使用,你太抽象了,反而不可理解,很多我们正常还是面向对象方便好编程。

    无状态
    何为无状态?简单点讲就是,函数内部涉及的变量都是局部变量,不会像面向对象编程那样,共享类成员变量,也不会像面向过程编程那样,共享全局变量。函数的执行结果只与入参有关,跟其他任何外部变量无关。同样的入参,不管怎么执行,得到的结果都是一样的。

    public int count(int a){
      int b = 1;
      return a+b;
    }
    
    public int count(int a,int b){
    return a+b;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面这俩第二个更符合无状态,因为第一个实际上b被改了之后,既保证不了,但是第二个什么情况,结果都是根据入参确定的,不会受到其他因素。

    不同的编程范式:

    面向对象的编程单元是类或对象,面向过程的编程单元是函数,函数式编程的编程单元是无状态函数。

    Java的函数表达式三个体现:stream。Lambda,函数式接口

    stream

    stream应该是用的最多的一个JDK8新特性,里面对应的很多方法,比如filter,map,groupBy等,但是要注意,实际上这些stream返回的都是一个Stream对象,而不是我们自己的对象,拿到的结果实际是从这个Stream对象转换出来的。

    以下是stream的filter,map的源码方法对应
    在这里插入图片描述

    如下所示。其中,map、filter 是中间操作,返回 Stream 类对象,可以继续级联其他操作;max 是终止操作,返回的不是 Stream 类对象,无法再继续往下级联处理了。

    
    public class FPDemo {
      public static void main(String[] args) {
        Optional result = Stream.of("f", "ba", "hello") // of返回Stream对象
                .map(s -> s.length()) // map返回Stream对象
                .filter(l -> l <= 3) // filter返回Stream对象
                .max((o1, o2) -> o1-o2); // max终止操作:返回Optional
        System.out.println(result.get()); // 输出2
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Lambda

    lambda现在很多地方也会用到,如果不理解确实会导致代码阅读性门槛高,看到一篇文章,对Lambda总结,就是一个-> 箭头 的使用用法,其实这个不一定确切,但是你不懂的情况下,这个说法可以让你在一堆介绍lambda的繁琐的文章中有个理解。

    lambda的结构

    
    (a, b) -> { 语句1; 语句2;...; return 输出; } //a,b是输入参数
    
    • 1
    • 2

    Lambda 表达式的写法非常灵活。我们刚刚给出的是标准写法,还有很多简化写法。比如,如果输入参数只有一个,可以省略 (),直接写成 a->{…};如果没有入参,可以直接将输入和箭头都省略掉,只保留函数体;如果函数体只有一个语句,那可以将{}省略掉;如果函数没有返回值,return 语句就可以不用写了。

    实际上Lambda是Java提供的一种语法糖,底层实现还是函数接口,只不过这些都没有展示出来,利用的是默认实现。

    下面代码是把上面代码的filte,map,max这些底层函数接口展示出来,这个你就能看到很多具体的步骤

    
    Optional result = Stream.of("f", "ba", "hello")
            .map(s -> s.length())
            .filter(l -> l <= 3)
            .max((o1, o2) -> o1-o2);
            
    // 还原为函数接口的实现方式
    Optional result2 = Stream.of("fo", "bar", "hello")
            .map(new Function() {
              @Override
              public Integer apply(String s) {
                return s.length();
              }
            })
            .filter(new Predicate() {
              @Override
              public boolean test(Integer l) {
                return l <= 3;
              }
            })
            .max(new Comparator() {
              @Override
              public int compare(Integer o1, Integer o2) {
                return o1 - o2;
              }
            });
    
    • 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

    函数接口

    Java 8 引入了 「 函数接口 」 ( funtional interface ) 的概念,「 函数接口 」就是那些有且只有显式定义一个方法的接口。

    如果一个接口的实现类只需要实现一个方法,那么该接口就是函数接口。

    具体来说,有以下两种情况

    1. 那些只有一个方法的接口,例如 Comparable 接口,它只有一个方法 compareTo()。
    2. 那些具有多个默认方法,但有且只有一个虚方法的接口。也就是说,函数接口也可以有多个方法,但除了一个可用 Lambda
      表达式来实现的方法,其它方法都必须有 default 关键字。

    实际上,函数接口就是接口。不过,它也有自己特别的地方,那就是要求只包含一个未实现的方法。因为只有这样,Lambda
    表达式才能明确知道匹配的是哪个接口。如果有两个未实现的方法,并且接口入参、返回值都一样,那 Java 在翻译 Lambda
    表达式的时候,就不知道表达式对应哪个方法了。

    Function、Predicate、Comparator 这些函数接口,他们包裹一个函数,把函数作为变量,弥补Java不能像,C语言那样把函数通过指针的方式直接使用。

    接口说明
    BiConsumer表示接受两个不同类型的参数,但不返回任何结果的操作
    BiFunction表示接受两个不同类型的参数,并返回一个其它类型的结果的操作
    BinaryOperator表示接受两个相同类型的参数,并返回一个同一类型的结果的操作
    BiPredicate表示接受两个不同诶行的参数,且返回布尔类型的结果的操作
    BooleanSupplier不接受任何参数,且返回一个布尔类型的结果的操作
    Consumer表示接受一个参数,但不返回任何结果的操作
    DoubleBinaryOperator表示接受两个 double 类型的参数,并返回 double 类型结果的操作
    DoubleConsumer表示接受一个 double 类型的参数,但不返回任何结果的操作
    DoubleFunction表示接受一个 double 类型的参数,且返回一个 R 类型的结果的操作
    DoublePredicate表示一个接受两个 double 类型的参数, 且返回一个布尔类型的结果的操作
    DoubleSupplier表示一个不接受任何参数,但返回布尔类型的结果的操作
    DoubleToIntFunction表示接受两个 double 类型的参数,但返回一个 int 类型的结果的操作
    DoubleToLongFunction表示接受两个 double 类型的参数,但返回一个 long 类型的结果的操作
    DoubleUnaryOperator表示接受一个 double 类型的参数,且返回一个 double 类型的结果的操作
    Function表示一个接受 T 类型的参数,且返回一个 R 类型结果的函数
    IntBinaryOperator表示一个接受两个 int 类型的参数,且返回一个 int 类型的结果的操作
    IntConsumer表示接受一个 int 类型的参数,但不返回任何结果的操作
    IntFunction表示接受一个 int 类型的参数,但返回一个 R 类型的结果的操作
    IntPredicate表示接受一个 int 类型的参数,但返回布尔类型的结果的操作
    IntSupplier表示不接受任何参数,但返回一个 int 类型的结果的操作
    IntToDoubleFunction表示接受一个 int 类型的参数,但返回一个 double 类型的结果的操作
    IntToLongFunction表示接受一个 int 类型的参数,但返回一个 long 类型的结果的操作
    IntUnaryOperator表示接受一个 int 类型的参数,且返回一个 int 类型的结果的操作
    LongBinaryOperator表示接受两个 long 类型的参数,且返回一个 long 类型的结果的操作
    LongConsumer表示不接受任何参数,但返回一个 long 类型的结果的操作
    LongFunction表示接受一个 loing 类型的参数,但返回一个 R 类型的结果的操作
    LongPredicate表示接受一个 long 类型的参数,但返回布尔类型的结果的操作
    LongSupplier表示不接受任何参数,但返回一个 long 类型的结果的操作
    LongToDoubleFunction表示接受一个 long 类型的参数,但返回一个 double 类型的结果的函数
    LongToIntFunctio表示接受一个 long 类型的参数,但返回 int 类型的结果的函数
    LongToDoubleFunction表示接受一个 long 类型的参数,但返回一个 double 类型的结果的函数
    LongToIntFunction表示接受一个 long 类型的参数,但返回 int 类型的结果的函数
    LongUnaryOperator表示接受一个 long 类型的参数,并返回一个 long 类型的结果的操作
    ObjDoubleConsumer表示接受两个参数,一个为 T 类型的对象,另一个 double 类型,但不返回任何结果的操作
    ObjIntConsumer表示接受两个参数,一个为 T 类型的对象,另一个 int 类型,但不返回任何结果的操作
    ObjLongConsumer表示接受两个参数,一个为 T 类型的对象,另一个 double 类型,但不返回任何结果的操作
    Predicate表示接受一个指定类型 T 的参数,但返回布尔类型的结果的操作
    Supplier表示不接受任何参数,但返回一个 T 类型的结果的操作
    ToDoubleBiFunction表示接受两个不同类型的参数,但返回一个 double 类型的结果的操作
    ToDoubleFunction表示一个接受指定类型 T 的参数,并返回一个 double 类型的结果的操作
    ToIntBiFunction表示接受两个不同类型的参数,但返回一个 int 类型的结果的操作
    ToIntFunction表示一个接受指定类型 T 的参数,并返回一个 int 类型的结果的操作
    ToLongBiFunction表示接受两个不同类型的参数,但返回一个 long 类型的结果的操作
    ToLongFunction表示接受两个不同类型的参数,但返回一个 long 类型的结果的操作
    UnaryOperator表示接受一个参数,并返回一个与参数类型相同的结果的操作
  • 相关阅读:
    医学影像工作站PACS系统源码,医院PACS系统源码
    数据结构——单链表(基本操作 一)
    JavaScript高级,ES6 笔记 第一天
    题目0144-最大利润
    Leetcode算法入门与数组丨4. 数组排序
    leetcode路飞吃桃,递归做法
    未来:spring响应式编程 Hands-On Reactive Programming in Spring 5 全书深度解读(一),为啥需要响应式编程
    【JavaScript】生成 [x, y]之间的随机整数
    Zookeeper面试题大全
    mysql和clickhouse数据同步 MaterializeMySQL 引擎
  • 原文地址:https://blog.csdn.net/FeiChangWuRao/article/details/127555113