在这个由三部分组成的系列文章中,我们一直在探索您可以在今天的Android项目中开始使用的所有主要Java 8功能。
在使用Lambda表达式的Cleaner Code中 ,我们专注于使用lambda表达式从您的项目中删除样板,然后在Default和Static Methods中 ,我们看到了如何通过将它们与方法引用结合来使这些Lambda表达式更简洁。 我们还介绍了重复注释,以及如何使用默认和静态接口方法在您的接口中声明非抽象方法。
在最后一篇文章中,我们将研究类型注释,功能接口,以及如何使用Java 8的新Stream API采取更具功能性的方法进行数据处理。
我还将向您展示如何使用Joda-Time和ThreeTenABP库访问Android平台当前不支持的其他Java 8功能。
类型注释
通过将诸如Lint之类的代码检查工具告知他们应该寻找的错误,注释可以帮助您编写更健壮且更不易出错的代码。 然后,如果一段代码不符合这些注释所列出的规则,这些检查工具将向您发出警告。
注释并不是一个新功能(实际上,它们可以追溯到Java 5.0),但是在Java的早期版本中,只能将注释应用于声明。
在Java 8发行版中,您现在可以在使用类型的任何地方使用注释,包括方法接收器; 类实例创建表达式; 接口的实现; 泛型和数组; throws
和implements
子句的规范; 并进行类型转换。
令人沮丧的是,尽管Java 8确实使在比以前更多的位置中使用注释成为可能,但是它没有提供任何特定于类型的注释。
Android的注释支持库提供对一些其他注释的访问,例如@Nullable
, @NonNull
以及用于验证资源类型的注释,例如@Nullable
, @NonNull
@DrawableRes
, @DimenRes
@ColorRes
和@StringRes
。 但是,您可能还需要使用第三方静态分析工具,例如Checker Framework ,该工具是与JSR 308规范(Java类型规范上的注释)共同开发的。 该框架提供了自己的一组注释,这些注释可以应用于类型,外加大量“检查器”(注释处理器),这些“钩子”可以插入到编译过程中,并对Checker框架中包含的每种类型注释执行特定的“检查”。
由于类型注释不影响运行时操作,因此可以在项目中使用Java 8的类型注释,同时保持与Java早期版本的向后兼容性。
流API
Stream API提供了另一种“管道和过滤器”方法来处理集合。
在Java 8之前,您通常通过遍历集合并依次对每个元素进行操作来手动操作集合。 这种显式的循环需要很多样板,此外,在到达循环主体之前,很难掌握for循环的结构。
通过对数据执行一次运行,Stream API为您提供了一种更有效地处理数据的方式,无论您要处理的数据量是多少,或者是否执行多次计算。
在Java 8中,每个实现java.util.Collection
类都有一个stream
方法,该方法可以将其实例转换为Stream
对象。 例如,如果您有Array
:
String[] myArray = new String[]{"A", "B", "C", "D"};
然后,您可以使用以下命令将其转换为Stream:
Stream<String> myStream = Arrays.stream(myArray);
通过一系列计算步骤(称为流管道) ,Stream API通过携带来自源的值来处理数据。 流管道由以下部分组成:
- 源,例如
Collection
,数组或生成器函数。 - 零个或多个中间“惰性”操作。 在调用终端操作之前,中间操作不会开始处理元素,这就是为什么它们被认为是惰性的。 例如,在数据源上调用
Stream.filter()
只是建立流管道。 在调用终端操作之前,实际上不会进行任何过滤。 这样就可以将多个操作串在一起,然后在一次数据传递中执行所有这些计算。 中间操作将产生一个新的流(例如,filter
将产生一个包含已过滤元素的流), 而无需修改数据源,因此您可以自由使用项目中其他地方的原始数据,也可以从同一源创建多个流。 - 终端操作,例如
Stream.forEach
。 当您调用终端操作时,所有中间操作将运行并产生一个新的流。 流无法存储元素,因此,一旦您调用终端操作,该流即被视为“已消耗”且不再可用。 如果您确实想重新访问流的元素,则需要从原始数据源生成一个新的流。
创建流
有多种方法可从数据源获取流,包括:
Stream.of()
根据单个值创建一个流: