那些年,我们追过的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那么返回新的collectorreturn 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迎接你的到来。

posted on 2017-08-31 17:47 在山的那边 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/foreveravalon/p/7459529.html

那些年,我们追过的java8相关推荐

  1. Java8 日期/时间(Date Time)API指南

    Java 8日期/时间( Date/Time)API是开发人员最受追捧的变化之一,Java从一开始就没有对日期时间处理的一致性方法,因此日期/时间API也是除Java核心API以外另一项倍受欢迎的内容 ...

  2. Linux下安装Java8

    Linux(ubuntu)下Java8安装 1.下载jdk8 这个看大家了,linux版本的就可以 2.创建jvm文件夹 在根目录下创建名为jvm的文件夹(在哪里创建看个人) $ sudo mkdir ...

  3. [2017.02.23] Java8 函数式编程

    以前学过Haskell,前几天又复习了其中的部分内容. 函数式编程与命令式编程有着不一样的地方,函数式编程中函数是第一等公民,通过使用少量的几个数据结构如list.map.set,以及在这些数据结构上 ...

  4. java增加final,Java8增加功能--Effectively final 功能

    java8新增了很多功能,可以大大简化代码,这个系列将会一一辅助代码加以介绍. 局部内部类和匿名内部类访问的局部变量必须由final修饰,java8开始,可以不加final修饰符,由系统默认添加.ja ...

  5. Java8中Lambda表达式的10个例子

    Java8中Lambda表达式的10个例子  例1 用Lambda表达式实现Runnable接口 Java代码   //Before Java 8: new Thread(new Runnable() ...

  6. java 跨年 周计算公式_如何跨年计算 两日期之间相隔的周数 with java8 time API

    ===============================2016年9月版 分割线======================================== 之前版本的我太simple了.. ...

  7. Java系列 – 用Java8新特性进行Java开发太爽了(续)

    本人博客文章网址:https://www.peretang.com/using-java8s-new-features-to-coding-is-awesome-2/ 前言 上周, 我们谈论了关于Ja ...

  8. Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法

    Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法 Java语言提供了一种功能强大的注释形式:文档注释.如果编写Java源代码时添加了合适的文档注释,然后通过JDK提供 ...

  9. Java8中Stream流对集合操作

    java8中Stream流引入函数式编程思想,主要配合各种接口.lambda表达式.方法引用等方式,为集合的遍历.过滤.映射等提供非常"优雅"的操作方式. Student.java ...

最新文章

  1. MATLAB【十四】————调用深度库生成exe,批量运行三层文件夹下图片,保存结果
  2. MSSQL 2005 分页分析及优化
  3. Java项目课程02:系统概述
  4. Java阻塞队列的实现
  5. 系统自带不起眼但很强杀毒工具
  6. 第4个HttpClient 例子,下载指定图片并保存到请定目录
  7. 复合线转权属线lisp_地籍成图之权属线绘制-快猴网.ppt
  8. 怎样学c语言编程软件,c语言编程软件(新手学c语言用什么软件)
  9. fc安卓模拟器_MAME街机模拟器0.224经典游戏全收藏
  10. css 剪辑图片_[译]用CSS剪切圆形图片
  11. Docker从入门到精通
  12. kafka-eagle 使用配置及远程jmx端口设置遇到的问题
  13. 一文了解美团团节社等及分佣机制
  14. LeetCode_1677_数组中重复的数字
  15. 云端新增长,混合云融合发展新路径 | 云端会客厅第28期精彩回顾
  16. CGroup(控制组)
  17. 支持居者有其屋,支持房产税出台与落地。
  18. 科学研究机构管理系统
  19. 推荐一些好用的APP
  20. deepinV20一路艰辛系列六:更新微信到最新版本

热门文章

  1. 图解CSS的padding,margin,border属性
  2. C语言文件操作基本常识
  3. Makefile的重建与include指令
  4. Linux基础(一)----- Linux常用命令
  5. mac的截图在linux下打不开,mac版截图软件Snip详细使用教程及常见问题
  6. 分布式入门,怎样用PyTorch实现多GPU分布式训练
  7. Android Bitmap面面观
  8. Apk去签名校验详解
  9. 验证码实现php 难点,php实现简单的验证码功能
  10. python3 logging模块_Python3之logging模块浅析