Java函数式编程

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

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

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

public int count(int a){
  int b = 1;
  return a+b;
}

public int count(int a,int b){
return a+b;
}

上面这俩第二个更符合无状态,因为第一个实际上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<Integer> result = Stream.of("f", "ba", "hello") // of返回Stream<String>对象
            .map(s -> s.length()) // map返回Stream<Integer>对象
            .filter(l -> l <= 3) // filter返回Stream<Integer>对象
            .max((o1, o2) -> o1-o2); // max终止操作:返回Optional<Integer>
    System.out.println(result.get()); // 输出2
  }
}

Lambda

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

lambda的结构


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

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

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

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


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

函数接口

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

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

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

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

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

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

接口说明
BiConsumer<T,U>表示接受两个不同类型的参数,但不返回任何结果的操作
BiFunction<T,U,R>表示接受两个不同类型的参数,并返回一个其它类型的结果的操作
BinaryOperator表示接受两个相同类型的参数,并返回一个同一类型的结果的操作
BiPredicate<T,U>表示接受两个不同诶行的参数,且返回布尔类型的结果的操作
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>表示一个接受 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<T,U>表示接受两个不同类型的参数,但返回一个 double 类型的结果的操作
ToDoubleFunction表示一个接受指定类型 T 的参数,并返回一个 double 类型的结果的操作
ToIntBiFunction<T,U>表示接受两个不同类型的参数,但返回一个 int 类型的结果的操作
ToIntFunction表示一个接受指定类型 T 的参数,并返回一个 int 类型的结果的操作
ToLongBiFunction<T,U>表示接受两个不同类型的参数,但返回一个 long 类型的结果的操作
ToLongFunction表示接受两个不同类型的参数,但返回一个 long 类型的结果的操作
UnaryOperator表示接受一个参数,并返回一个与参数类型相同的结果的操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值