原因:Java8所做的改变,在许多方面比Java历史上任何一次改变都深远,且熟练掌握它们会让你编程更容易,效率更高。
优点一:简化代码
如,在Java8之前,写一个对集合排序的程序需要这样写:
Collections.sort(inventory, new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
现在可以简化为:
inventory.sort(comparing(Apple::getWeight));
优化二:更方便安全的使用并发编程
以为使用线程和锁的方式使用复杂,容易出错。Java5中的concurrent包有了一定改善,但还是有一定的门槛。现在Java8出现了新思路,即函数式并发。
优化三:Stream API
重大特性,可方便的针对集合做批量操作,跟sql类似,只要指示做什么,具体细节怎么做由底层自动实现。
流(Stream)是一系列数据项,一次只生成一项。程序可以从输入流中一个一个读取数据项,然后以相同的方式将数据项写入输出流。一个程序的输入流很可能是另一个程序的输出流。
UNIX中流的示例:
cat file1 file2 | tr “[A-Z]” “[a-z]” | sort | tail -3
cat程序可将file1和file2文件合起来生成一个流,通过管道“|”将程序连在一起,前一个输出流作为后一个程序的输入流,以此形成强大的功能。
Java8中吸取该思想,在java.util.stream中添加了Stream API。 Stream API中的很多方法可以链接起来形成一个复杂的流水线。这样我们可以在更高抽象层次上编码,从一次只处理一项转变为流的转换。另一个好处是可以透明的把输入的不相干的部分拿到几个CPU上分别执行流水线上的操作,这几乎是免费的并行。
优化四:函数式编程
现在方法不仅能接受参数,对象,也能接受行为,即行为参数化。现在Java8可以把方法作为参数传递给另一个方法。将代码传递给方法的功能称为函数式编程。
优化五:新日期API
使用诸如LocalDate, LocalTime来实现强大的日期时间处理功能。
Java中的函数
在Java中通常用方法(method)指代函数。另外函数也指没有副作用的函数,如数学中的函数,这样的函数的执行结果仅跟传入参数有关,跟当前对象的状态无关,所有很多纯静态类中的静态方法都符合这个特征,如java.lang.Math中的方法。
java中传统方法参数只能传值,值有8个原生变量值,对象引用,现在Java8中新加入了函数(方法),它作为值的一种新形式。
方法和Lambda
实践证明让方法能作为值传递能让编程更强大,也是其他功能(Stream API)的基础。
可作为方法参数值的形式:
一、方法引用
如:File::isHidden。 由类名加“::”分隔符,再加方法名构成。后面会再详细讲方法引用
二、Lambda(匿名函数)
除了允许传递命名函数(方法引用)外,还可以直接传递lambda表达式(匿名函数),如:
int x -> x + 1, 表示调用时给丁参数x, 返回x+1的结果。
后面会详细讲Lambda。当我们程序采用函数式编程风格时,即意味着:编写把函数作为值来传递的程序。
流(Stream)
几乎每个Java应用都会制造和处理集合,但集合用起来总是不理想。实现一些看起来不复杂的功能却需要大量的代码,如假设需要从一个交易列表中做筛选,筛选出金额较高的交易,然后按货币分组。如果用传统代码遍历实现,大概是这样:
如果使用我们Java8的Stream API,则可以简化为:
Map<Currency, List<Transaction>> transactionsByCurrencies =
transactions.stream()
.filter(t -> t.getPrice() > 1000)
.collect(groupingBy(Transaction::getCurrency));
可以看出简化很多,可读性也很强。如果用传统集合需要用for-each迭代,再自行处理,这种方法我们称为外部迭代。相反用了StreamAPI,循环不用操心,只要告诉如何做就行,这可称为内部迭代。
另外StreamAPI可充分利用并行,如上述的过滤集合,内部可自动分片,在不同的CPU上执行,最后合并在一起。
默认方法
Java8新增的默认方法打破了长久以来接口没有实现的约定。之所以这么做,是为了支持库设计师,让他们能够写出更容易改进的接口,而不会破坏现有的代码。具体原因后面会讲。本身需要编写默认方法的需求不多。
如List中新增了如下默认方法:
default void sort(Comparator<? super E> c) {
Collections.sort(this, c);
}
这意味着List的任何实现子类都不需要显示实现sort方法,而以前的版本必须实现,否则会编译错误。
Optional
使用描述性的数据类型来避免null。如果一致性的使用它,可以帮助我们避免出现NullPointer异常,它是一个Holder对象(容器),可以包含,也可以不包含一个值。
小结
本节简略了过了一下Java8的新特性,以及为什么需要学习,带来了哪些好处。对方法引用,lambda,Stream API,default method, Optional做了简要介绍。