Stream流的使用
stream流运算是java8中很重要的一个计算特性,个人认为是和lamda表达式(下次有时间介绍一下lamda表达式)一样,在实际项目中应用价值很高。使用stream编程,代码简洁,函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。同时,对于多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。
基本概念
工作中使用频率很高的“技能树”。下面来介绍一下这个方法的使用。 Java 8 中的 Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
Stream API 借助于同样新出现的 Lambda表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join 并行方式来拆分任务和加速处理过程。
在Stream API中,一个流基本上代表一个元素序列,Stream API提供了丰富的操作函数来计算这些元素。以前我们在开发业务应用时,通常很多操作的实现是这样做的:我们使用循环对集合做遍历,针对集合中的元素实现各种操作,定义各种变量来实现目的,这样我们就得到了一大堆丑陋的顺序代码,大大降低编码的数量级。
stream流的一些基本用法:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered、forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator、anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
下面就一些常见的用法给出介绍:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
使用并行流使程序性能更好。
基本用法介绍:
并行流处理parallelStream
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl","jljjojo","ddff");
count = strings.parallelStream().filter(string -> string.isEmpty()).count();
结果截图为:
使用了parallelStream进行流式处理,同时使用了过滤条件filter,最后使用count进行统计
filter
上面的截图中使用到了filter。统计处理strings中为空的字符串的个数。
map
它的作用就是把 input Stream 的每一个元素,映射成 output Stream 的另外一个元素。map 方法用于映射每个元素到对应的结果
map的使用方法如下:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
squaresList = numbers.stream().map( i ->i*34343).collect(Collectors.toList())
计算的结果为:
sorted
将上面的stream流加上了sorted后
squaresList = numbers.stream().map( i ->i*34343).sorted().collect(Collectors.toList())
我们可以看一下结果:
很明显的发现结果经过了排序,从小到大进行了排列。
anyMatch、noneMatch和allMatch
strings.stream().anyMatch(x ->x.isEmpty())
strings.stream().noneMatch(x ->x.isEmpty())
strings.stream().allMatch(x ->x.isEmpty())
anyMatch:表示有一个满足条件即为true,其他情况为false。
noneMatch:表示没有一个满足即为true,其他为false。
allMatch:表示所有的必须都满足,此时为true,其他情况为false。
下面是分别使用anyMatch、noneMatch和allMatch的结果:
reduce
integers.stream().reduce(0,(q,b)->q+b)
对integers中的数据进行累加和
运行后的结果:
peek
squaresList = numbers.stream().map( i ->i*4).peek(e -> System.out.println("map value:"+ e)).collect(Collectors.toList())
mapToInt 、limit和summaryStatistics
mapToInt:对原数据进行转换处理
limit:限制数据输出的数量
summaryStatistics:用来对数据进行总数、累加和、最大值和最小值的统计。
integers.stream().mapToInt((x) ->3*x).limit(3).summaryStatistics()
distinct
distinct:把集合中的重复的元素去掉。
integers.stream().distinct().findFirst()
findFirst
findFirst:从字面意思为,取集合中的第一个元素。
sorted
排序的方法:按照顺序排列集合中的元素
integers.stream().distinct().sorted().collect(Collectors.toList())
skip
去掉集合中开始的元素
integers.stream().skip(2).collect(Collectors.toList())
比对上面的结果可以发现,最开始的元素消失了。
代码实践:
在项目中,实际上遇到了合并两个封装类的请求,而使用通常的for循环,代码量相对很大,同时,让后来者看起来比较难理解,所以引入了stream流来处理这个问题。
分别有两个封装类:Employee和Person
package Stream;
/**
* Created by Administrator on 2019/6/31.
*/
public class Employee {
private String job;
private double salary;
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getPersonID() {
return personID;
}
public void setPersonID(int personID) {
this.personID = personID;
}
private int personID;
public Employee(int id, String job, double salary){
this.setJob(job);
this.setPersonID(id);
this.setSalary(salary);
}
}
package Stream;
/**
* Created by Administrator on 2019/7/15.
*/
public class Person {
public Person(int id, String name, int age){
this.setPersonID(id);
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
public int getPersonID() {
return personID;
}
public void setPersonID(int personID) {
this.personID = personID;
}
private int personID;
}
原始数据
package Stream;
import java.util.Arrays;
import java.util.List;
/**
* Created by Administrator on 2019/7/15.
*/
public class Db {
List<Person> getPerson(){
return Arrays.asList(new Person(1,"xiaoming", 25), new Person(2,"zhangsan", 24), new Person(3,"wangwu", 22), new Person(4,"xiaofang", 66));
}
List<Employee> getEmployee(){
System.out.println("get called");
return Arrays.asList(new Employee(1, "designer", 10000), new Employee(3, "coder", 12000), new Employee(2, "coder", 13000), new Employee(5, "tester", 9000));
}
}
现在需要把两个数据通过序号合并到一起
package Stream;
import org.apache.commons.beanutils.BeanMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
通过下面的方式合并了
/**
* Created by Administrator on 2019/7/15.
*/
public class Join {
public static void main(String[] args) throws Exception {
Db inst = new Db();
List<Employee> es = inst.getEmployee();
List r = inst.getPerson().stream().map(p ->
es.stream().filter(e -> e.getPersonID() == p.getPersonID()).findFirst().map(e -> {
Map s = new HashMap();
s.putAll(new BeanMap(e));
s.putAll(new BeanMap(p));
return s;
}).orElse(null)
).filter(p -> p != null).collect(Collectors.toList());
r.forEach(System.out::println);
}
}
把两边的数据进行合并,结果就能返回所需要的值。