Java8的新特性

Java8的新特性

一. 引文

Java 8是改动较大的一个版本,新增了Lambda表达式、函数式编程、流等,当然也有一些其他扩充功能的更新。这些变化主要反映了Java从注重改变现有值得经典面向对象思想转变为向函数式编程领域转变。这些改动会很大程度上对开发人员起到帮助,让编程更容易更轻松。

对于并发编程来说,Java 1.0时有线程和锁,甚至提供了内存模型,但没有相关专业知识的团队很难可靠的使用这些工具。Java 5时添加了工业级的构建模块,如线程池和并发集合。Java 7时添加了分支/合并(fork/join)框架,使得并行变得更加实用,但依旧会有些困难。Java 8则对并行提供了一个更简单的新思路。

二. 三个新的编程概念

2.1 流处理

流是一系列数据项,一次只生成一项。程序可以从输入流中一个一个读取数据项,以相同方式将数据项写入输出流。

比如在Unix或Linux中,很多程序从标准输入中读取数据(Unix和C中的stdin,Java中的System.in),然后把结果写入标准输出(Unix和C中的stdout,Java中的System.out)。如下命令,cat会把两个文件连接起来创建一个流,tr会转换流中的字符,sort会对流中的行进行排序,trail -3则会给出流的最后三行。Unix允许这些程序通过管道(|)连接起来。

1
cat file1 file2 | tr "[A-Z]" "[a-z]" | sort | trail -3

上述语句会先把字母转为小写,然后打印出排序后的最后三个单词。sort会把一个行流作为输入,产生了另一个行流,进行排序并输出。在Unix中,这些命令是同时执行的,就像工厂式的流水线,虽然整个命令序列像是是一步一步完成的,但各个命令的运行是并行的。

基于此思想,Java 8在java.util.stream中添加了一个Stream API;可以把Stream看作是一个迭代器,它可以链接起来形成一个流水线。它带来的好处就是我们可以像SQL那样写查询语句的思路,把这样的流转为那样的流,而不是一次只能处理一个项目,而且Java可以很透明的把输入中不相关的部分分开放到几个CPU内核上分别执行,这样自动的并行就省去我们去开辟线程的功夫了。

2.2 用行为参数化把代码传递给方法

比如我们有一组学生数据,包括其年龄,学期成绩,班级,学号等信息,我们可能有各种排序需求,真正想要的就是通过给sort一个参数让其定义顺序。我们可以写一个函数compareUsingAge来比较学生的年龄,但Java 8之前我们没法把这个方法传递给另一个方法,所以只能创建一个Comparator对象,然后把对象传递给sort方法。而有了行为参数化后,这样的需求就可以简单的实现了,我们可以把compareUsingAge方法作为参数传递给sort。

把代码传递给方法这种方式简洁的表达了行为参数化,也许你会想可以通过匿名类实现行为参数化,但Lambda和方法引用可以更清晰和简单的来实现这一需求。

2.3 并行与共享的可变数据

如果我们的代码可以拆分为多个副本并独立工作时,并行是可以确保的,但如果要写入一个共享变量或对象,如果两个线程都要同时修改这个变量,就是不能允许的了。当然你可以通过synchronized来打破不能有共享的可变数据这一原则,但打破的同时也就意味着放弃了所有相关的优化,同步就意味着要按照顺序执行,这与并行的宗旨相悖。

没有共享的可变数据将代码传递给方法的能力这两个概念是函数式编程范式的基石。而相反的命令式编程范式中,程序是一系列改变状态的指令。

Java 8为并行做的优化:

  • 库会负责分块,把大的流分成几个小的流,以便于并行处理。
  • 流所提供的这个免费并行,只有在传递给filter之类的库方法的函数不会互动时才能工作。函数式编程中函数的主要意思是函数可以作为一等值,但也隐含着执行时元素间无互动的意思。

把代码传递给方法(方法引用、Lambda)和接口中的默认方法这两种特性的补充可以看作是为Stream而设计的

三. 行为参数化

行为参数化

四. 默认方法

默认方法

五. Lambda表达式

Lambda表达式

Lambda异常处理方案

六. 流

流(一)入门介绍

流(二)使用和构建

流(三)收集器

流(四)并行化处理

七. 重构、测试和调试

重构、测试和调试

八. Optional

Optional

九. CompletableFuture组合式异步编程

CompletableFuture组合式异步编程

十. 新的日期和时间API

新的日期和时间API

十一. 函数式的思考

函数式的思考

十二. 函数式编程的技巧

函数式编程的技巧


参考:

🔗 《Java8实战》