zoukankan      html  css  js  c++  java
  • 那些年,我们追过的java8

    9月份java9就要发布了,在8月的最后一天决定回顾一下java8那些惊天动地的变化,加深理解,共同进步。

    我们都知道java与c++,c不同是一个为面向对象而生的语言,面向对象思想贯彻了java发展的大部分时间直到java8,java8的出现为java引进了新的思想(虽然这个思想在别的语言里早就有了)--函数式编程,这是两种思想的碰撞,导致刚刚接触java8会觉得自己不是在写java代码。。。好了废话不多说,先总结java8的一些颠覆性的变动点:

    1.接口允许有实现:

    public interface MyInterface {
    
        default String getResult(){
            return "hello world!";
        }
    }

    这叫默认实现,据说是为了foreach而引进的,默认方法实现带来了另一个问题--多重继承,但是又不是完全意义上的多重继承,因为继承的是方法,相当于无状态多重继承。所以必须有一些规则来处理多重继承所带来的问题:

    • 继承最近的接口的默认方法。
    • 使用重写后的方法
    • 当使用以上规则后仍无法确认时,会报错

    2.集合

    java8对集合的处理才是重头戏。先来看看几个常见的函数式接口:

    Consumer

    Supplier

    Operator

    Function

    以及在此基础上的一些扩展

    BiConsumer

    BinrayOperator

    BiFunction

    接口就不一一介绍,可以看一下源码,也很简单,就是定义了函数的处理方式抽象了各种不同的函数

    集合中最常用的工具类:Collectors是本次分析的主角。

    在看Collectors类之前,必须先看看一个接口:Collector

    它有三个类型:入参类型,中间类型,出参类型,这个接口是干什么的呢,通过它定义的参数,我们基本上可以猜到,它定义了一系列函数,将入参经过一系列处理,变化,得到另一个结果。源码上有一系列注释,说明了这个类的作用,这里简单翻译一下:

    Collector是一个由4个函数组成的,用来做相当于reduce的惰性求值的类。这4个函数是:

    Supplier<A> supplier();--用来生成存放惰性求值结果的容器
    BiConsumer<A, T> accumulator();--用来计算入参,并将结果放入容器的函数
    BinaryOperator<A> combiner();--用来将两个容器合并成一个容器。(这个是一个fork/join的一个重要步骤)
    Function<A, R> finisher();--将容器中结果转化为想要的结果的函数。
    其实它还有第5个参数,表明COllector是线程安全的还是不安全的或者A就是R不需要最后一步。

    Collector就介绍到这里,在Collectors里有Collector的默认实现。

    Collectors里面定义了诸多工具方法,不过,为了展示函数式编程的魅力,我们挑一个长一点的出来分析一把:groupingBy方法,源码如下:
    public static <T, K, D, A, M extends Map<K, D>>
        Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                      Supplier<M> mapFactory,
                                      Collector<? super T, A, D> downstream) {
            Supplier<A> downstreamSupplier = downstream.supplier();  //获取downstream的容器函数
            BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();    //获取downstream的reduce操作的计算函数
            BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {                                                      //将计算结果放入map中的函数(也是新的collector的计算函数)
                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
                A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());        //这步是关键,通过map的key来判断是不是同一类,如果是同一类,则返回原来的容器,否则则使用downstream的函数创建一个容器
                downstreamAccumulator.accept(container, t);                                   //为容器填充值
            };
            BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());  //获取合并函数
            @SuppressWarnings("unchecked")
            Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;  //该函数返回结果容器函数(Map类型)
    
            if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {            //如果downstream的类型是IDENTITY_FINISH那么返回新的collector
                return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
            }
            else {
                @SuppressWarnings("unchecked")
                Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();  //否则获取计算结果的函数
                Function<Map<K, A>, M> finisher = intermediate -> {                             //生成新的结果函数
                    intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                    @SuppressWarnings("unchecked")
                    M castResult = (M) intermediate;
                    return castResult;
                };
                return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
            }
        }

    先看注释中的一段例子:

    Map<Department, Integer> totalByDept
              = employees.stream()
                       .collect(Collectors.groupingBy(Employee::getDepartment,
                                                        Collectors.summingInt(Employee::getSalary)));

    这个例子是计算公司每个部门员工工资综合,具体的pojo就不给不来了。

    纵观整个过程,groupingBy将downstream(Collector)(直译:下游流)按照classfier的规则分类,将结果放入由mapFactory函数生成的Map容器中,返回新的Collector。我们看到,如何由一个老的Collector经过一系列处理,变为新的Collector,其实至此仍未结束,我们仍可以对
    新的Collector做更多操作,这些操作都不会发生,直到我们调用了及早求值的方法,真正的操作才会发生,如上面的stream.collect,函数式编程操作的不再是数据,而是一个个函数,可以看做一个函数对另一个函数的装饰从而形成新的函数。
    总之,函数式编程已经不仅仅是思想,也是一种编程习惯,如果我们不用,不写,即使说再多,也是纸上谈兵。
    java8还是要更多练习与探索的。
    java9迎接你的到来。







  • 相关阅读:
    ASP.NET的内置对象 —— Response 对象
    dd命令测试硬盘IO
    Linux netstat命令详解
    tpcc-mysql安装、使用、结果解读
    【MySQL案例】error.log的Warning:If a crash happens thisconfiguration does not guarantee that the relay lo(转)
    mysql5.6主从
    无法远程访问Mysql
    pythonMD5加密
    python随机验证码函数
    log buffer space事件(转)
  • 原文地址:https://www.cnblogs.com/foreveravalon/p/7459529.html
Copyright © 2011-2022 走看看