《软件架构基础》- 函数式编程

假装没事ソ 提交于 2020-02-25 23:16:26

函数式编程

它属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用

特点

  • 函数作为一等公民
$("button").click(function(){
    $("li").each(function(){
      alert($(this).text())
    });
  });
  • 无副作用

    • 函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外部的状态,比如,函数在调用过程中,修改了某一个全局状态。函数式编程认为,函数的副用作应该被尽量避免。
    • 函数做了除了约定之外的其它事情
  • 引用透明

    • 引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或“状态”,只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。
  • 申明式的(Declarative)

    • 相对于命令式(imperative)而言,命令式的程序设计喜欢大量使用可变对象和指令

    • 申明式的编程:申明你的用意

      public static void imperative(){ 
          int[] iArr={1,3,4,5,6,9,8,7,4,2}; 
          for(int i=0;i<iArr.length;i++){ 
              System.out.println(iArr[i]);
         } 
      }
      public static void declarative(){  
          int[] iArr={1,3,4,5,6,9,8,7,4,2};
          Arrays.stream(iArr).forEach(System.out::println);
      }
      
  • 不变模式

    static int[] arr={1,3,4,5,6,7,8,9,10};
    Arrays.stream(arr).map((x)->x=x+1).forEach(System.out::println);
    System.out.println();
    Arrays.stream(arr).forEach(System.out::println);
    
  • 易于并行

    • 不变模式天生是并行的
    • 引用透明
  • 更少的代码

    • 属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用
    • 如 (1 + 2) * 3 - 4
    subtract(multiply(add(1,2), 3), 4)
    
    • 变形后
    add(1,2).multiply(3).subtract(4)
    
  • 易于阅读的

为什么使用

  • 易于并行
  • 易于进行数据处理
  • 更好的模块化
  • 高效的(可工作的软件 重于 详尽的文档)
  • 回归简单

java8

  • @FunctionalInterfacce

  • lambda表达式

    • lambda表达式即匿名函数,它是一段没有函数名的函数体
    • 可以作为参数
    • lambda中访问外部变量视为final
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);  
    numbers.forEach((Integer value) -> System.out.println(value));
    
    final int num = 2;
    Function<Integer, Integer> stringConverter = (from) -> from * num;
    System.out.println(stringConverter.apply(3));
    
  • 方法引用

    • 静态方法引用:ClassName::methodName
    • 实例上的实例方法引用:instanceReference::methodName
    • 超类上的实例方法引用:super::methodName
    • 类型上的实例方法引用:ClassName::methodName
    • 构造方法引用:Class::new
    • 数组构造方法引用:TypeName[]::new

java8函数式编程基础

  • Stream 一组待处理的数据
  • Predicate 谓词 ,返回是或不是
  • Function 将一个对象映射成另一个元素
  • BiFunction 将两个对象映射成一个对象
  • Consumer 消费者, 放在终结操作,即最后对元素做什么
  • BiConsumer消费两个对象,,产生某种行为
  • Supplier有返回值的Runable

基于Stream的操作

  • forEach
  • filter
  • map
  • reduce
  • collect
  • peek

操作分类

  • 中间函数与惰性求值

    • 中间函数返回一个流,程序中可以多次地、串接地调用流的操作,因为中间操作如映射map、过滤filter函数返回一个流对象。这类操作具有惰性。虽然代码写出了对它们 的调用,但是并没有真正执行。
  • 结尾函数

    • 结尾函数返回一个值或void函数产生一个副作用/side effect。

foreach

  • 结尾函数

    Arrays.stream(new int[]{1,2,3,5}).forEach(x->System.out.println(x));
    

filter

  • 接收一个谓词操作,如果谓词返回true,那么当前元素就会被处理,如果谓词返回false,那么元素就会被简单的丢弃

    static int[] arr={1,3,4,5,6,7,8,9,10};
    public static void main(String[] args) {
    	Arrays.stream(arr).filter((x)->x%2==0).forEach(System.out::println);
    }
    

map

  • 对元素进行映射

    static int[] arr={1,3,4,5,6,7,8,9,10};
    public static void main(String[] args) {
    	Arrays.stream(arr).map((x)->x*x).forEach(System.out::println);
    }
    

reduce

  • 对元素进行汇聚

    collect

  • 将元素转为集合

peek

  • 监视,调试

Optional

  • 一个用于处理NULL的对象
  • 用于传递可能为NULL的意图
  • 避免NULL打断程序流,使程序流更顺创

Optional的核心API-1

  • public boolean isPresent()
    
    • 判断当前值是否存在。相当于null检查。
  • public void ifPresent(Consumer<? super T> consumer)
    
    • 相对于进行null的判断,如果值有意义,则进行consumer操作。
  • public static <T> Optional<T> of(T value)
    
    • 这是一个工厂方法,构造一个包装了value的Optional。
  • public static <T> Optional<T> ofNullable(T value)
    
    • 工厂方法,如果value为null,则返回empty对象。否则等同于of()函数。

Optional的核心API-2

  • public T get()
    
    • 返回Optional内的包装对象。如果为null,则抛出一个异常。
  • public Optional<T> filter(Predicate<? super T> predicate)
    
    • 判断当前值是否满足predicate条件。如果不满足,则返回一个empty。
  • public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
    
    • 通过mapper,对当前的值做一个转换。
  • public T orElse(T other)
    
    • 如果当前值为空,则给一个默认的other作为值。
  • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
    
    • 如果值为空,则抛出一个异常。
  • stus.stream()
        .forEach(
            (x)->Arrays.stream(x.getScores())
                .average()
                .ifPresent(System.out::println)
        );
    

Optional经验分享

  • 尽量不要直接使用get(),isPresent()方法
  • 尽量依赖map() orElse() 等等
  • Optional和异常不兼容

数据流上统计操作

  • IntStream对数据流提供了便捷的统计操作

  • average()

  • count()

  • sum()

  • max()

    static Comparator<Student> aveScore=(u1,u2)->ave(u1)>ave(u2)?1:-1;
    public static double ave(Student stu){
        return Arrays.stream(stu.getScores()).average().orElse(0);
    }
    public static void main(String[] args) {
        //取得平均分最高的同学
        stus.stream().max(aveScore).ifPresent(System.out::println);
    }
    
  • min()

Collector接口

对流中的元素进行收集和汇聚操作

元素收集到一个集合中

字符串拼接

统计计算 max min sum

  • 创建结果容器
  • 将新元素加入容器
  • 合并两个容器
  • 执行最终转换操作得到结果(可选)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!