JDK Streams — 行云流水般地编码
Streams 简介
JDK 8已经发布好一段时间,在JDK 8中新增了好些开发人员期许的功能;从性能、开发效率上都有提升。也引入了很多全新的API ,如 java.util.stream
包下的
Stream及其相关 Stream API。
java.util.stream.Stream与java.io包里的InputStream或OutputStream有本质的区别,它和IO流无关。Stream API类似于具有Iterable功能的集合类,但其行为和集合类又有所不同,它在操作集合对象功能上有极致的发挥,可以非常简洁、高效地操作大批量数据。另外;普遍受到开发人员欢迎的函数式编程也可在Stream API开发应用中体现得淋漓尽致。Stream API充分利用Lambda表达式的编码特性和函数式编程的特点;让代码看起来更加简洁和易读。编码起来如行云流水一般。下面就Stream API的一些特点用一个例子简单来体验它的强大和编码上的享受。
Streams 应用
1. 类定义、初始化数据
定义一个Student类,其中包括有一个全参的构造方法和isGzStudent()方法; 这个方法主要用于判断学生的名字中是否包含“广州“,如果包含则返回true,否则返回false。
接着再写一个常规类StreamRocks,主要用于测试Stream的各方法。在StreamRocks中初试化了一个包含Student对象的集合students,该集合也是之后测试的数据来源,由于数值不再变动,所以设定为final。
2. 代替常规循环
以前在输出集合内容时,最常见的做法是使用循环语句,如for/while等将
集合内元素一个个遍历并取出其属性值输出。Stream的forEach为这样的遍历操作提供了简便,配合Lambda表达式;可如下代替常规循环:
上面的forEach用于遍历stream中的对象,由于接受Lambda表达式,则再将形参stu对应的Student对象取出学生姓名再输出。
forEach(stu -> System.out.println(stu.getName()))
等价于
for(Student stu:students){
System.out.println(stu.getName());
}
3. 不再烦扰匿名类——自定义对象排序
两个对象之间进行属性数值比较的话,在以前往往需要写一个匿名比较器类Comparator,并在实现compare()方法,在方法中进行比较并返回比较值;同样地Stream结合Lambda,可以将匿名类的实现编写为如下:
(s1,s2) -> s1.getAge() – s2.getAge() 等价于实现了Comparator里面的compare()方法;如下:
public int compare(Student s1, Student s2){
return s1.getAge() – s2.getAge();
}
4. 集合数据条件过滤
集合数据中如果需要根据一定的条件筛选过滤内容,典型做法是逐个遍历集
合对象,然后再将符合条件的对象设置到新的集合中;代码量多且多余。Stream的filter()方法接受符合特定条件(Predicate)的对象的过滤。官方对这个方法的描述为:
大致意思是:在原有的stream中找到符合匹配查询条件的元素并返回一个新stream。有了这个过滤方法,可以对集合中的数据进行任意条件的过滤。
filter(student -> "女".equals(student.getGender())) 过滤保留集合中的学生对象的性别为 女 的学生对象。
5. 集合数据统计
mapToInt()可以将原Stream中的每个对象进行操作并返回一个
整型数值重新生成一个
IntStream,然后再调用IntSteam中的计算平均值的方法average()。
需要注意的是,上述代码中使用了 方法引用;maptToInt(Student::getAge)
等价于 maptToInt(stu -> stu.getAge())
计算学生总年龄上使用了parallelStream() ,该方法返回的Stream被称为并行Stream,即可以并行地执行这个Stream将要执行的操作以此提高效率。需要注意的是虽然所有可以返回Stream的对象都可以返回并行Stream,不过并行Stream并非就是最好的,它总是牺牲其它不相关代码的执行效率;需要慎重使用。
6. 数据匹配
在数据集合中查找是否具有某特征的数据,在Stream中是极其容易的;调用match相关的方法可以返回你想要的逻辑相关数据条件组合结果。
anyMatch(Student::isGzStudent) 的执行操作为:在学生对象集合中查询学生的姓名中是否包含有广州两个字,有则返回true否则返回false。
7. 数据归约
在集合中如需要按照一定规则对所有数据进行递减式的操作;那么Stream的reduce()方法是个好选择。reduce()在执行规则的过程时记录结果并将结果与集合剩余元素按照规则进行处理。处理完后返回一个
Optional类型的容器对象。
上述代码主要目的是将原是Student对象的Stream转为一个以Student的姓名为对象的新Stream,然后再调用reduce((str1, str2) -> { return str1 + "," + str2;})将新Stream中的所有元素字符拼接起来。
从上述的Stream简单应用中可发现,在常用的集合数据或大批量数据的操作时方法容易,代码简洁;这样引入bug的机会就少,当bug出现时,代码量少也更容易排查。